What is Nitro?
Nitro is a framework for building powerful and fast native modules in React Native.
- A Nitro Module is a library built with Nitro. It contains one or more Hybrid Objects.
- A Hybrid Object is a native object in Nitro, implemented in either C++, Swift or Kotlin.
- Nitrogen is a code-generator a library author can use to generate native bindings from a custom TypeScript interface.
interface Math extends HybridObject {
readonly pi: number
add(a: number, b: number): number
}
class HybridMath : HybridMathSpec {
var pi: Double {
return Double.pi
}
func add(a: Double, b: Double) -> Double {
return a + b
}
}
This Hybrid Object can then be accessed directly from JS:
const math = NitroModules.createHybridObject<Math>('Math')
const result = math.add(5, 7)
Performance
Nitro is all about performance. This benchmark compares the total execution time when calling a single native method 100.000 times:
ExpoModules | TurboModules | NitroModules | |
---|---|---|---|
100.000x addNumbers(...) | 434.85ms | 115.86ms | 7.27ms |
100.000x addStrings(...) | 429.53ms | 179.02ms | 29.94ms |
Note: These benchmarks only compare native method throughput in extreme cases, and do not necessarily reflect real world use-cases. In a real-world app, results may vary. See NitroBenchmarks for full context.
Lightweight layer
While Nitro is built on top of JSI, the layer is very lightweight and efficient.
Many things like type-checking is compile-time only, and built with C++ templates or constexpr
which introduces zero runtime overhead.
Direct Swift <> C++ interop
Unlike Turbo- or Expo-Modules, Nitro-Modules does not use Objective-C at all. Nitro is built using the new Swift <> C++ interop, which is close to zero-overhead.
Uses jsi::NativeState
Hybrid Objects in Nitro are built on top of jsi::NativeState
, which is more efficient than jsi::HostObject
. Such objects have proper native prototypes, and their native memory size is known, which allows the garbage collector to properly clean up unused objects.
Type Safety
Nitro Modules are type-safe and null-safe. By using Nitro's code-generator, nitrogen, TypeScript specs are the single source of truth as generated native interfaces have to exactly represent the declared types.
If a function declares a number
, you can only implement it on the native side as a Double
, otherwise the app will not compile.
interface Math extends HybridObject {
add(a: number, b: number): number
}
class HybridMath : HybridMathSpec {
func add(a: Double, b: Double) -> String {
// Compile-error: Expected Double! ^
return a + b
}
}
Null-safety
There is no way for a Nitro Module to return a type that is not expected in TypeScript, which also guarantees null-safety.
interface Math extends HybridObject {
getValue(): number
getValueOrNull(): number | undefined
}
Object-Oriented approach
Every Hybrid Object in Nitro is a native object, which can be created, passed around, and destroyed.
interface Image extends HybridObject {
readonly width: number
readonly height: number
saveToFile(path: string): Promise<void>
}
interface ImageEditor extends HybridObject {
loadImage(path: string): Promise<Image>
crop(image: Image, size: Size): Image
}
Functions (or "callbacks") are also first-class citizens of Nitro, which means they can safely be kept in memory, called as often as needed, and will automatically be cleaned up when no longer needed. This is somewhat similar to how other frameworks (like Turbo-Modules) implement "events".
Modern Languages
Nitro is a modern framework, built on top of modern languages like Swift and Kotlin. It has first-class support for modern language features.
Swift
Nitro bridges to Swift directly using the new highly efficient Swift <> C++ interop.
- Protocols: Every Hybrid Object's generated specification is a Swift protocol.
- Properties: A getter (and setter) property can be implemented using Swift properties.
- Async/Await: Asynchronous functions can use Swift's new async/await syntax using the
Promise.async
API. - No Objective-C: Instead of bridging through Objective-C interfaces, Nitro bridges to Swift directly from C++.
Kotlin
Nitro bridges to Kotlin directly using fbjni.
- Interfaces: Every Hybrid Object's generated specification is a Kotlin interface.
- Properties: A getter (and setter) property can be implemented using Kotlin properties.
- Coroutines: Asynchronous functions can use Kotlin's coroutine syntax using the
Promise.async
API. - No Java: Instead of requiring Java classes, Nitro bridges to Kotlin directly.