Why TurboModules?
The legacy native module system had several limitations:- Eager initialization - All modules loaded at startup, even if never used
- Bridge overhead - JSON serialization for every call
- No type safety - Type mismatches only caught at runtime
- Async-only - All calls asynchronous, even for simple getters
- Memory waste - Unused modules consume memory
- Lazy loading - Modules initialized only when first accessed
- JSI direct calls - No serialization overhead
- Codegen type safety - Compile-time type checking
- Synchronous calls - Support both sync and async methods
- Efficient - Smaller memory footprint and faster startup
Architecture
TurboModule Base Class
All TurboModules extend the base class defined inReactCommon/react/nativemodule/core/ReactCommon/TurboModule.h:
- HostObject - TurboModules are JSI HostObjects, accessible from JavaScript
- Method metadata - Each method has metadata (arg count, invoker function)
- Call invoker - Schedules work on appropriate threads
- Lazy method binding - Methods bound to JavaScript objects on first access
Method Value Kinds
TurboModule methods can return different types:Creating a TurboModule
1. Define JavaScript Spec
Create a spec file using TypeScript or Flow:2. Run Codegen
Codegen generates the native interfaces:MyModuleSpec.h- C++ abstract base class- iOS:
MyModuleSpec-generated.mm- Objective-C++ glue code - Android:
MyModuleSpec.java- Java/Kotlin interfaces
3. Implement Native Code
iOS Implementation (Objective-C++)
Android Implementation (Kotlin)
4. Register Module
iOS
Add to your TurboModule provider:Android
Add to package:5. Use in JavaScript
Lazy Loading
TurboModules are initialized lazily:- Faster startup - Only frequently-used modules loaded
- Lower memory - Unused modules never allocated
- On-demand - Modules loaded exactly when needed
Eager Initialization
For modules that must be loaded at startup:Synchronous vs Asynchronous Methods
Synchronous Methods
Return values directly:Asynchronous Methods
Return promises:CallInvoker and Threading
TheCallInvoker schedules work on appropriate threads:
Scheduling JavaScript Callbacks
Thread Requirements
Specify where methods should execute:Type Safety with Codegen
Codegen ensures type safety across the boundary:Primitive Types
Complex Types
Enums
Constants and Configuration
Modules can export constants:- Evaluated once - At module initialization
- Cached - Same object returned for all calls
- Synchronous - No async access needed
Event Emission
TurboModules can emit events to JavaScript:For type-safe events, use EventEmitter from Codegen specs instead of NativeEventEmitter.
Error Handling
Promise Rejection
Throwing Synchronous Errors
Performance Considerations
Minimize JSI Calls
Each JSI call has overhead. Batch operations:Avoid Large Data Transfers
Serializing large objects has cost:Use ArrayBuffer for Binary Data
Cache Results
Migration from NativeModules
Legacy NativeModule
TurboModule
Key Differences
Debugging
Enable TurboModule Logs
iOS:Verify TurboModule Loading
Further Reading
Codegen
Learn how Codegen generates native interfaces
JavaScript Interface
Understand JSI powering TurboModules
Architecture Overview
See how TurboModules fit in the architecture
Threading Model
Understand threading in new architecture