Skip to main content
TurboModules are React Native’s next-generation native module system, replacing the legacy NativeModules. Built on JSI, TurboModules provide lazy loading, type safety through Codegen, and direct synchronous communication between JavaScript and native code.

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
TurboModules solve these problems:
  • 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 in ReactCommon/react/nativemodule/core/ReactCommon/TurboModule.h:
Key concepts:
  • 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:
Codegen automatically determines the correct kind based on your TypeScript/Flow spec.

Creating a TurboModule

1. Define JavaScript Spec

Create a spec file using TypeScript or Flow:

2. Run Codegen

Codegen generates the native interfaces:
Outputs:
  • 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:
Benefits:
  • 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:
Synchronous methods block the JavaScript thread. Keep them fast (less than 1ms) or users will experience jank.

Asynchronous Methods

Return promises:

CallInvoker and Threading

The CallInvoker 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

Codegen converts to native enums (iOS) or constants (Android).

Constants and Configuration

Modules can export constants:
Constants are:
  • 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:
Android:

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