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.







