Skip to main content

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.
Math.nitro.ts
interface Math extends HybridObject {
readonly pi: number
add(a: number, b: number): number
}
HybridMath.swift
class HybridMath : HybridMathSpec {
var pi: Double {
return Double.pi
}
func add(a: Double, b: Double) -> Double {
return a + b
}
}

Performance

Nitro is all about performance. This benchmark compares the total execution time when calling a single native method 100.000 times:

ExpoModulesTurboModulesNitroModules
100.000x addNumbers(...)434.85ms115.86ms7.27ms
100.000x addStrings(...)429.53ms179.02ms29.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 ontop 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 ontop 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.

Math.nitro.ts
interface Math extends HybridObject {
add(a: number, b: number): number
}
HybridMath.swift
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 ontop 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.