Welcome to Day 20 of the React Native Advent Calendar!
Today we’re comparing the three ways to build native modules in React Native. Whether you need to access device features, optimize performance, or integrate native libraries, you have three powerful options!
The Three Contenders
Building native functionality in React Native has evolved significantly. Today, you have three modern approaches:
- TurboModules - Meta’s official solution for the New Architecture
- Expo Modules - Expo’s developer-friendly approach with Swift & Kotlin
- Nitro Modules - Mark Rousavy’s high-performance C++ framework
Each has different strengths, trade-offs, and ideal use cases. Let’s break them down.
1. TurboModules: Meta’s Official Solution
TurboModules are Meta’s official way to build native modules for React Native’s New Architecture.
What They Are
TurboModules use Codegen to automatically generate native interfaces from TypeScript or Flow type definitions. You write a typed JavaScript spec, and Codegen creates the native glue code for both iOS and Android.
Key Benefits
- Official React Native solution - First-class support from Meta
- Type-safe - TypeScript/Flow specs enforce type safety
- Automated code generation - Codegen eliminates boilerplate
- New Architecture native - Built for the modern RN runtime
- Cross-platform - Single spec for iOS and Android
Example: Simple TurboModule Spec
import type { TurboModule } from 'react-native';
import { TurboModuleRegistry } from 'react-native';
export interface Spec extends TurboModule {
createCalendarEvent(name: string, location: string): Promise<boolean>;
getCurrentTime(): number;
}
export default TurboModuleRegistry.getEnforcing<Spec>('NativeCalendar');When to Use TurboModules
Use TurboModules when:
- You’re building for apps using the New Architecture
- You want official Meta support
- You need maximum compatibility with RN ecosystem
- You’re comfortable with C++/Objective-C++
2. Expo Modules: Developer Experience First
Expo Modules prioritize developer experience with modern Swift and Kotlin APIs.
What They Are
Expo Modules let you write native code in Swift (iOS) and Kotlin (Android) with significantly less boilerplate than traditional approaches. They use JSI (same as TurboModules) for performance.
Key Benefits
- Modern languages - Swift & Kotlin instead of Objective-C/Java
- Minimal boilerplate - Expo’s API reduces code by ~90%
- Great DX - Fast iteration, clear APIs, helpful errors
- Performance - JSI-based, comparable to TurboModules
- Works everywhere - Compatible with New Architecture AND legacy
- Autolinking - Automatic native dependency linking
Example: Simple Expo Module
import ExpoModulesCore
public class CalendarModule: Module {
public func definition() -> ModuleDefinition {
Name("Calendar")
// Async function
AsyncFunction("createEvent") { (name: String, location: String) -> Bool in
// Create calendar event
return true
}
// Synchronous function
Function("getCurrentTime") { () -> Double in
return Date().timeIntervalSince1970
}
}
}That’s it! No bridge code, no manual type conversions, no Codegen configuration.
When to Use Expo Modules
Use Expo Modules when:
- You want the best developer experience
- You prefer Swift/Kotlin over C++/Objective-C
- You need backward compatibility with legacy apps
- You want minimal boilerplate
3. Nitro Modules: High-Performance C++
Nitro Modules by Mark Rousavy (creator of react-native-vision-camera) focus on maximum performance through C++.
What They Are
Nitro generates type-safe bindings from TypeScript interfaces, creating a zero-overhead bridge between JavaScript and native C++ code. It’s designed for performance-critical modules.
Key Benefits
- Maximum performance - Highly optimized JSI with caching
- Type-safe across languages - TypeScript → C++ → Swift/Kotlin
- C++ power - Direct C++ integration for complex algorithms
- Minimal overhead - Lightweight memory footprint
- Flexible types - Supports primitives, objects, arrays, variants
- HybridObjects - JavaScript-like objects with native backing
Example: Nitro Module Interface
interface HybridCalendar extends HybridObject {
createEvent(name: string, location: string): Promise<boolean>;
getCurrentTime(): number;
// Nitro supports complex types seamlessly
getAllEvents(): CalendarEvent[];
}
interface CalendarEvent {
id: string;
name: string;
startDate: Date;
attendees: string[];
}Nitrogen (Nitro’s codegen) generates:
- Type-safe C++ bindings
- Swift/Kotlin implementations
- Zero-copy data transfer where possible
When to Use Nitro Modules
Use Nitro Modules when:
- Performance is absolutely critical
- You’re building compute-intensive features (image processing, ML, etc.)
- You need C++ integration for third-party libraries
- You want zero JavaScript-to-native overhead
- You’re comfortable with C++
The Verdict: Which Should You Use?
For Most Developers: Expo Modules 🏆
Expo Modules offer the best balance of:
- Developer experience
- Performance
- Compatibility
- Community support
For Performance-Critical Apps: Nitro Modules ⚡
Choose Nitro when:
- You’re building vision/ML features
- You need C++ integration
- Performance is non-negotiable
For RN Core Contributors: TurboModules 🏛️
TurboModules make sense when:
- Contributing to React Native core
- Building official Meta libraries
- Maximum ecosystem compatibility required
Wrapping Up
The native module landscape in React Native has matured significantly. You have three excellent options, each with clear strengths.
Quick recap:
- TurboModules - Meta’s official solution, great for core RN work
- Expo Modules - Best DX, modern languages, works everywhere
- Nitro Modules - Maximum performance, C++ power, cutting-edge
Ready to build native modules?
Built a native module? Share your experience on Twitter!
Tomorrow we’ll explore Day 21’s topic - see you then! 🎄