React Native Library with a Native Module: New Architecture, JSI, TurboModules
Developing a mobile app often hits proprietary SDKs from vendors — integration with biometrics, cameras, or MDM systems. Off-the-shelf libraries from React Native Community rarely cover these cases, so you need to write a native module from scratch. We've been doing this for over 5 years, delivering more than 10 projects with native modules for iOS and Android. Our experience shows that choosing the right architecture slashes development time by 2–3x.
Old Architecture vs New Architecture: Core Differences
| Parameter | Old Architecture (Bridge) | New Architecture (TurboModules + JSI) |
|---|---|---|
| Invocation mechanism | Asynchronous, via JSON serialization | Synchronous, direct C++ binding |
| Latency | 1–5 ms per call | < 0.1 ms |
| Thread handling | JS thread blocks on synchronous calls | JS thread not blocked (different model) |
| React Native version support | 0.68 and below | 0.73+ (enabled by default) |
New Architecture uses JSI (JavaScript Interface) — a direct C++ binding between the JS engine (Hermes) and native code. TurboModules are lazy-loaded and invoked synchronously. For high-frequency operations (every animation frame, real-time audio processing), this is critical: performance difference reaches 5–10x. The library must support both variants via the codegen specification.
Why New Architecture Is Faster
The old Bridge works asynchronously via JSON serialization. A native method call goes: JavaScript → JSON serialization → Bridge queue → deserialization → Java/ObjC. This adds ~1–5 ms per call and makes synchronous access to native code impossible. New Architecture uses JSI (JavaScript Interface) — a direct C++ binding between the JS engine (Hermes) and native code. TurboModules are lazy-loaded and invoked synchronously. For high-frequency operations (every animation frame, real-time audio processing), this is critical.
React Native 0.73+ includes New Architecture by default. The library must support both variants via the codegen specification.
How to Create a Library via create-react-native-library
npx create-react-native-library@latest my-module — standard scaffold. Generates structure:
my-module/ android/src/main/java/…/MyModule.kt ios/MyModule.mm (Objective-C++ for JSI bridge) src/index.tsx — TypeScript API src/NativeMyModule.ts — codegen spec Codegen Specification
The TypeScript file describes the contract from which codegen generates C++ glue code:
// 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>; getDeviceId(): string; // synchronous method — only in New Architecture } export default TurboModuleRegistry.getEnforcing<Spec>('MyModule'); getEnforcing throws an error at startup if the native module is not registered — better than silent undefined.
Android Implementation: Kotlin + ReactPackage
class MyModule(reactContext: ReactApplicationContext) : NativeMyModuleSpec(reactContext) { override fun getName() = NAME override fun multiply(a: Double, b: Double): Promise<Double> { return Promise.resolve(a * b) } override fun getDeviceId(): String { return Settings.Secure.getString( reactApplicationContext.contentResolver, Settings.Secure.ANDROID_ID ) } companion object { const val NAME = "MyModule" } } NativeMyModuleSpec is an abstract class generated by codegen from the TypeScript spec. If a method is not implemented — compile-time error, not runtime crash. This is a key advantage of New Architecture.
ReactPackage registers the module:
class MyPackage : ReactPackage { override fun createNativeModules(context: ReactApplicationContext) = listOf(MyModule(context)) override fun createViewManagers(context: ReactApplicationContext) = emptyList<ViewManager<*, *>>() } iOS: Objective-C++ Bridge
For New Architecture, iOS implementation is written in Objective-C++ (.mm) or Swift with ObjC wrapper. Swift does not natively support JSI without a bridge, so an .mm file with #import <React/RCTUtils.h> remains mandatory.
// MyModule.mm #import "MyModule.h" #import <React/RCTUtils.h> @implementation MyModule RCT_EXPORT_MODULE() - (NSString *)getDeviceId { return [[[UIDevice currentDevice] identifierForVendor] UUIDString]; } @end For synchronous methods in Old Architecture: RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD — it works but blocks the JS thread. In New Architecture, synchronicity via JSI does not block the JS thread — a fundamentally different model.
Native View Components
If the task requires a custom native View (e.g., SDK maps, custom video player), we use ViewManager on Android / RCTViewManager on iOS. New Architecture introduces Fabric for native components — analogous to TurboModules for views. Codegen generates ComponentDescriptor from a TypeScript spec with codegenNativeComponent.
Expo Support
If the app uses Expo managed workflow, the native module requires the Expo Modules API instead of bare React Native. npx create-expo-module generates the correct scaffold. ExpoModule is registered automatically without ReactPackage — Expo Autolinking finds the module via package.json.
Typical Errors
Module not found at runtime
Forgot to run `pod install` on iOS after adding the module.Mismatched types
TypeScript spec says `number`, Kotlin accepts `Double` (ok), Swift accepts `Int` (crash). All numbers in JS are `Double` on the native side.Main thread violation
Calling UI code from a native method without dispatching to the main thread: `DispatchQueue.main.async` / `UiThreadUtil.runOnUiThread`.What's Included in Turnkey Native Module Development
Our engineers (5+ years of React Native experience) deliver:
- Requirements analysis and module API design
- Native code implementation in Kotlin and Objective-C++/Swift
- TypeScript specification code generation and New Architecture integration
- Unit and integration tests for both platforms
- Build and publication to npm/Expo registry
- Module documentation and usage examples
- Post-release support (bug fixes, updates for new RN versions)
Estimated Timelines
| Module Type | Timeline |
|---|---|
| Simple (1–3 methods) | 3 to 5 days |
| Complex (EventEmitter, View, both architectures) | 3 to 5 weeks |
Cost is calculated individually. We will assess your project — contact us for a consultation.
How We Guarantee Quality
Using codegen eliminates runtime compile-time errors. Every module is tested on real devices (iOS 15+ and Android 10+). We provide a compatibility certificate with the latest React Native versions. We guarantee free support for 30 days after delivery.
According to official React Native documentation, JSI reduces per-call latency from 1–5 ms to <0.1 ms.
Order native module development — get a consultation from our engineers.







