Everything-react-native-expo native-module-scaffold

Guided wizard for creating Turbo Modules and Expo Modules with iOS and Android implementations

install
source · Clone the upstream repo
git clone https://github.com/JubaKitiashvili/everything-react-native-expo
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/JubaKitiashvili/everything-react-native-expo "$T" && mkdir -p ~/.claude/skills && cp -r "$T/.claude/skills/native-module-scaffold" ~/.claude/skills/jubakitiashvili-everything-react-native-expo-native-module-scaffold && rm -rf "$T"
manifest: .claude/skills/native-module-scaffold/SKILL.md
source content

Native Module Scaffold

You are creating a native module for React Native. This skill guides you through the entire process from TypeScript API design to native implementations.

When to Use This Skill

Invoke when:

  • Need to access native platform APIs not available in React Native
  • Building a bridge between JavaScript and Swift/Kotlin
  • Creating a custom UI component with native rendering
  • Integrating a native SDK

Module Type Selection

Option A: Expo Modules API (Recommended for Expo projects)

Simplest approach. Uses

expo-modules-core
for bridging:

npx create-expo-module my-module

Generated structure:

modules/my-module/
  expo-module.config.json
  src/MyModuleModule.ts          # TypeScript API
  ios/MyModuleModule.swift        # Swift implementation
  android/src/.../MyModuleModule.kt  # Kotlin implementation
  src/__tests__/MyModule.test.ts

Option B: Turbo Modules (For bare RN / New Architecture)

Lower level, more control. Uses codegen from TypeScript spec:

Step 1: Define TypeScript spec

// NativeMyModule.ts
import type { TurboModule } from 'react-native';
import { TurboModuleRegistry } from 'react-native';

export interface Spec extends TurboModule {
  multiply(a: number, b: number): Promise<number>;
  getDeviceInfo(): { model: string; os: string; version: string };
}

export default TurboModuleRegistry.getEnforcing<Spec>('MyModule');

Step 2: Implement iOS (Swift)

@objc(MyModule)
class MyModule: NSObject {
  @objc func multiply(_ a: Double, b: Double, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
    resolve(a * b)
  }

  @objc func getDeviceInfo() -> [String: String] {
    return [
      "model": UIDevice.current.model,
      "os": UIDevice.current.systemName,
      "version": UIDevice.current.systemVersion
    ]
  }
}

Step 3: Implement Android (Kotlin)

class MyModuleModule(reactContext: ReactApplicationContext) :
  NativeMyModuleSpec(reactContext) {

  override fun multiply(a: Double, b: Double): Promise {
    return Promise.resolve(a * b)
  }

  override fun getDeviceInfo(): WritableMap {
    return Arguments.createMap().apply {
      putString("model", Build.MODEL)
      putString("os", "Android")
      putString("version", Build.VERSION.RELEASE)
    }
  }
}

Option C: Fabric Components (For custom native views)

For custom UI components rendered natively:

// NativeMyView.ts
import type { ViewProps } from 'react-native';
import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent';

interface NativeProps extends ViewProps {
  color?: string;
  radius?: number;
}

export default codegenNativeComponent<NativeProps>('MyView');

Post-Scaffold Checklist

  • TypeScript types match native implementations
  • Error handling uses reject/Promise.reject with error codes
  • Threading: heavy work on background thread, UI on main
  • Memory: cleanup listeners and subscriptions
  • Platform parity: same API surface iOS and Android
  • Tests cover the TypeScript API
  • README documents usage