← All shorts
34React Native 0.73+2 min read

TurboModules: Lazy Native Modules and Codegen

TurboModules load native modules lazily and type-check them via codegen instead of the untyped NativeModules bridge.

Register a module on NativeModules and it gets instantiated at app launch. Whether you call it or not.

The calls into it are untyped on top of that, so a renamed native method fails the first time JS actually reaches for it — at runtime, in production if you're unlucky.

#The old way

import { NativeModules } from 'react-native';

const { DeviceInfo } = NativeModules;

async function getBatteryLevel(): Promise<number> {
  return DeviceInfo.getBatteryLevel();
}

Nothing checks that DeviceInfo exists. Nothing checks that getBatteryLevel is spelled the same way on the native side. You find out when this line executes.

#The new way

import { TurboModuleRegistry, type TurboModule } from 'react-native';

export interface Spec extends TurboModule {
  getBatteryLevel(): Promise<number>;
}

export default TurboModuleRegistry.getEnforcing<Spec>('DeviceInfo');
import DeviceInfo from './NativeDeviceInfo';

async function getBatteryLevel(): Promise<number> {
  return DeviceInfo.getBatteryLevel();
}

Codegen reads the Spec interface in NativeDeviceInfo.ts and writes the matching Objective-C++/Java glue at build time. A missing or mis-typed native method breaks the build instead of surprising you at runtime. And the module itself isn't constructed until the first time JS touches TurboModuleRegistry.getEnforcing.

#Why it matters

  • Startup cost scales with the modules you actually call, not every module linked into the app.
  • Signature drift between JS and native gets caught at build time.
  • The typed spec doubles as the contract documentation for the native side.

#Gotcha

Codegen does static analysis, not runtime discovery. It matches on the file's conventional name and on a literal interface Spec extends TurboModule. Rename the spec file away from NativeDeviceInfo.ts, or swap the interface for a type alias, and the module drops out of the codegen output. Silently. No error until you try to call it.

react-nativenative-modules

Related shorts