Nitro Modules React Native 2026: Native Modules Type-Safe Nhanh Hơn 15x TurboModules

Hướng dẫn thực chiến Nitro Modules trên React Native 0.83: từ TypeScript spec, cài đặt, Swift/Kotlin implementation đến benchmark hiệu năng gấp 15x TurboModules và kinh nghiệm migrate.

Cập nhật: 01 tháng 9, 2026

Nitro Modules là framework thế hệ mới do Marc Rousavy (tác giả VisionCamera, MMKV) phát triển, cho phép viết native module React Native type-safe bằng cách khai báo TypeScript interface và tự sinh code C++/Swift/Kotlin, nhanh hơn TurboModules tới 15 lần nhờ zero-overhead binding trên JSI. Trong bài này tôi tổng hợp lại toàn bộ những gì đội platform của tôi đã học sau ba tháng port ba module quan trọng (crypto, image pipeline, BLE bridge) từ TurboModules sang Nitro Modules trên React Native 0.83 và New Architecture.

  • Nitro Modules dùng JSI + Hybrid Objects thay cho Codegen của TurboModules, cho tốc độ gọi hàm ~15x, throughput ArrayBuffer gấp 3–5 lần.
  • Bạn khai báo HybridObject bằng TypeScript, sau đó chạy nitro-codegen để sinh spec C++, Swift protocol và Kotlin interface.
  • Yêu cầu bắt buộc: New Architecture bật (Fabric + Bridgeless), React Native ≥ 0.75, Expo SDK ≥ 51 với prebuild.
  • Hybrid Objects hỗ trợ trả về Promise, callback, ArrayBuffer, view-shadow và các HybridObject khác, không cần serialize.
  • Nitro Views (từ 0.20) cho phép viết Fabric native view type-safe trong 1 file, thay thế hoàn toàn codegenNativeComponent.
  • Chi phí migrate không cao nếu module không dùng NativeEventEmitter. Bạn chỉ cần map lại spec và xoá Codegen section trong package.json.

Nitro Modules là gì và tại sao ra đời

Nitro Modules là một hệ thống binding native cho React Native, xây dựng trực tiếp trên JSI (JavaScript Interface) mà không dùng codegen kiểu TurboModules chính thức. Cốt lõi của Nitro là khái niệm Hybrid Object, một đối tượng vừa tồn tại trong JavaScript (như một class TypeScript) vừa có phần cài đặt native tương ứng bằng Swift hoặc Kotlin, thông qua bridge C++ do nitro-codegen tự sinh.

Thật lòng mà nói, tôi bắt đầu chú ý đến Nitro khi phải port module mã hoá AES-256 GCM cho một app ngân hàng. TurboModule khi đó chỉ hỗ trợ tham số kiểu Object hoặc Array, không có ArrayBuffer zero-copy, khiến mỗi lần mã hoá 1 MB dữ liệu bị JSON.stringify hai lần và tốn ~40ms chỉ cho serialize. Với Nitro, cùng payload đó chạy dưới 3ms, không copy, và interface type-safe end-to-end. Đó là lý do project như VisionCamera 4, react-native-mmkv 3, react-native-quick-crypto 1.0 đều đã chuyển hoàn toàn sang Nitro Modules.

Về mặt kiến trúc, Nitro có ba lớp: (1) TypeScript spec định nghĩa Hybrid Object, (2) code C++ auto-generated dùng jsi::HostObject trực tiếp, (3) Swift/Kotlin implementation kế thừa protocol/interface sinh ra. Nếu bạn đã đọc bài về Kiến Trúc Mới React Native 2026 với Fabric và Bridgeless, Nitro có thể coi là "TurboModules được thiết kế lại từ đầu" mà không cần chịu gánh nặng backward compatibility với bridge cũ.

Nitro Modules khác gì với TurboModules?

Ở góc nhìn của architect, ba khác biệt lớn nhất giữa Nitro Modules và TurboModules là (1) hệ kiểu, (2) hiệu suất binding, và (3) hỗ trợ Hybrid Objects. TurboModules dùng Codegen của React Native để sinh interface từ Spec.ts, nhưng chỉ hỗ trợ tập kiểu giới hạn (primitive, Object, Array, Promise, callback). Nó không có ArrayBuffer trực tiếp, không có object-to-object binding, và không phân biệt readonly vs mutable.

Tính năngNitro ModulesTurboModules
Type systemĐầy đủ TypeScript: union, tuple, ArrayBuffer, Function, HybridObjectGiới hạn: string, number, boolean, Object, Array, Promise
Zero-copy bufferCó (ArrayBuffer trực tiếp qua JSI)Không, phải encode base64 hoặc JSON
Overhead gọi hàm (μs, iPhone 15)~1.2 μs~17 μs
Hybrid Objects (native class giữ state)Có, first-classKhông, phải mô phỏng bằng ID + map
Native view codegenNitro Views (từ 0.20)codegenNativeComponent + shadow node C++ tay
Yêu cầu New ArchitectureBắt buộcBắt buộc
Expo AutolinkingCó (từ nitro 0.18)
Ngôn ngữ nativeSwift, Kotlin, C++Objective-C++, Java, C++

Một điểm mà đội tôi rất thích: Nitro cho phép return một HybridObject khác từ một method. Ví dụ, CryptoModule.createCipher() có thể trả về một HybridCipher giữ state key/IV native, và các lần gọi tiếp theo không cần đi qua JS map. Với TurboModules, bạn phải trả về UUID string rồi tự quản dictionary trong native (tôi đã viết pattern này ba lần và mỗi lần đều gặp race condition).

Cài đặt Nitro Modules trong dự án React Native 0.83

Trước khi cài, xác nhận môi trường: React Native ≥ 0.75 (khuyến nghị 0.83), New Architecture bật cả iOS và Android, Xcode ≥ 15.4, Kotlin ≥ 1.9, và Node ≥ 20. Với Expo, bạn cần expo prebuild và Expo SDK ≥ 51. Sau đó cài package chính.

npm install react-native-nitro-modules
# hoặc yarn
yarn add react-native-nitro-modules

# Với module tự viết, cài devtool codegen
npm install --save-dev nitro-codegen

Trong package.json của module, khai báo cấu hình Nitro:

{
  "name": "react-native-crypto-nitro",
  "version": "1.0.0",
  "nitro": {
    "cxxNamespace": ["margelo", "nitro", "crypto"],
    "ios": {
      "iosModuleName": "NitroCrypto"
    },
    "android": {
      "androidNamespace": ["com", "margelo", "nitro", "crypto"],
      "androidCxxLibName": "NitroCrypto"
    },
    "autolinking": {
      "HybridCrypto": {
        "swift": "HybridCrypto",
        "kotlin": "HybridCrypto"
      }
    }
  },
  "scripts": {
    "codegen": "nitro-codegen",
    "prepare": "nitro-codegen"
  }
}

Cuối cùng, trong ios/Podfileandroid/build.gradle, đảm bảo autolinking đã bật (mặc định trong Expo Autolinking hoặc React Native community CLI 15+). Chạy cd ios && pod install sẽ tự thêm NitroModules pod và các subspec cho module bạn viết.

Viết Hybrid Object đầu tiên: TypeScript spec đến native code

Bước 1 là định nghĩa interface trong src/specs/HybridCrypto.nitro.ts. File .nitro.ts là quy ước để nitro-codegen nhận biết.

import type { HybridObject } from 'react-native-nitro-modules'

export interface Cipher extends HybridObject<{ ios: 'swift'; android: 'kotlin' }> {
  update(chunk: ArrayBuffer): ArrayBuffer
  final(): ArrayBuffer
  destroy(): void
}

export interface Crypto extends HybridObject<{ ios: 'swift'; android: 'kotlin' }> {
  readonly version: string

  randomBytes(size: number): ArrayBuffer
  createCipher(algorithm: 'aes-256-gcm', key: ArrayBuffer, iv: ArrayBuffer): Cipher
  hashAsync(algorithm: 'sha256' | 'sha512', data: ArrayBuffer): Promise<ArrayBuffer>
}

Chạy npx nitro-codegen sẽ sinh: nitrogen/generated/ios/HybridCryptoSpec.swift, nitrogen/generated/android/kotlin/HybridCryptoSpec.kt, và các file C++ trong nitrogen/generated/shared. Codegen cũng tạo hàm helper JS createHybridObject('Crypto') để lấy instance.

// src/index.ts
import { NitroModules } from 'react-native-nitro-modules'
import type { Crypto } from './specs/HybridCrypto.nitro'

export const Crypto = NitroModules.createHybridObject<Crypto>('Crypto')

// Sử dụng trong ứng dụng
const key = Crypto.randomBytes(32)
const iv = Crypto.randomBytes(12)
const cipher = Crypto.createCipher('aes-256-gcm', key, iv)
const encrypted = cipher.update(plaintext) // plaintext: ArrayBuffer
const tag = cipher.final()
cipher.destroy()

Triển khai native: Swift với Nitro protocol và Kotlin với Hybrid class

Codegen sinh ra HybridCryptoSpec ở dạng Swift protocol và Kotlin abstract class. Bạn viết implementation ở ios/HybridCrypto.swift.

import Foundation
import NitroModules
import CommonCrypto
import CryptoKit

class HybridCrypto: HybridCryptoSpec {
  var version: String { "1.0.0" }

  func randomBytes(size: Double) throws -> ArrayBufferHolder {
    var data = Data(count: Int(size))
    let status = data.withUnsafeMutableBytes {
      SecRandomCopyBytes(kSecRandomDefault, Int(size), $0.baseAddress!)
    }
    guard status == errSecSuccess else { throw RuntimeError.error(withMessage: "SecRandom failed") }
    return ArrayBufferHolder.copy(data: data)
  }

  func createCipher(algorithm: String, key: ArrayBufferHolder, iv: ArrayBufferHolder) throws -> HybridCipherSpec {
    return HybridCipher(algorithm: algorithm, key: key.toData(copy: true), iv: iv.toData(copy: true))
  }

  func hashAsync(algorithm: String, data: ArrayBufferHolder) throws -> Promise<ArrayBufferHolder> {
    return Promise.async {
      let bytes = data.toData(copy: false)
      let digest: Data = algorithm == "sha512"
        ? Data(SHA512.hash(data: bytes))
        : Data(SHA256.hash(data: bytes))
      return ArrayBufferHolder.copy(data: digest)
    }
  }
}

Trên Android, Kotlin sinh sẵn HybridCryptoSpec abstract:

package com.margelo.nitro.crypto

import com.margelo.nitro.core.*
import java.security.SecureRandom
import java.security.MessageDigest

class HybridCrypto : HybridCryptoSpec() {
  override val version: String = "1.0.0"
  private val rng = SecureRandom()

  override fun randomBytes(size: Double): ArrayBuffer {
    val bytes = ByteArray(size.toInt()).also(rng::nextBytes)
    return ArrayBuffer.copy(bytes)
  }

  override fun createCipher(algorithm: String, key: ArrayBuffer, iv: ArrayBuffer): HybridCipherSpec {
    return HybridCipher(algorithm, key.getBuffer(false), iv.getBuffer(false))
  }

  override fun hashAsync(algorithm: String, data: ArrayBuffer): Promise<ArrayBuffer> = Promise.async {
    val md = MessageDigest.getInstance(if (algorithm == "sha512") "SHA-512" else "SHA-256")
    md.update(data.getBuffer(false))
    ArrayBuffer.copy(md.digest())
  }
}

Điểm đáng chú ý: ArrayBufferHolder.copy(data:false) trên iOS và ArrayBuffer.getBuffer(false) trên Android trả về pointer trực tiếp vào JS heap. Bạn KHÔNG được giữ pointer này sau khi hàm return (JS engine có thể GC). Nếu cần lưu, gọi phiên bản copy: true để clone. Tôi hit đúng bug này trong lần ship đầu tiên: một Bitmap được cache 2 giây rồi crash khi truy cập, mất nửa buổi mới ra nguyên nhân.

Nitro Views: cách viết Fabric native view type-safe

Từ Nitro 0.20 (phát hành tháng 5/2026), Nitro Views cho phép viết Fabric native view (như một UIView/ViewGroup tuỳ chỉnh) hoàn toàn qua Hybrid Object, thay thế codegenNativeComponent vốn cần viết thêm shadow node C++ bằng tay. Đây là tính năng tôi đợi lâu nhất. Trước đó, viết một Fabric view như CustomMapView ngốn gần 2 tuần chỉ để hoàn thiện props diffing và event emission.

// src/specs/HybridCustomView.nitro.ts
import type { HybridView } from 'react-native-nitro-modules'

interface CustomViewProps {
  color: string
  radius: number
  onTap?: (x: number, y: number) => void
}

interface CustomViewMethods {
  focus(): void
  blur(): void
}

export type HybridCustomView = HybridView<CustomViewProps, CustomViewMethods>

Codegen tự sinh Fabric shadow node C++, host component descriptor, event emitter, và Kotlin/Swift base class. Bên native chỉ cần override beforeUpdate, afterUpdate để áp props và emit onTap qua emit(name, payload). React component sử dụng bình thường.

import { HybridCustomView } from 'react-native-nitro-modules'

<HybridCustomView
  color="#0EA5E9"
  radius={12}
  onTap={(x, y) => console.log('tap', x, y)}
  style={{ width: 200, height: 200 }}
/>

Toàn bộ props đều type-check ở compile time. Bạn viết color={12} sẽ đỏ ngay trong IDE, khác với codegenNativeComponent vốn để lộ lỗi ra runtime.

Có dùng Nitro Modules với Expo được không?

Câu trả lời ngắn: có, nhưng bạn phải chạy expo prebuild và không thể dùng Nitro Modules trong Expo Go. Từ Expo SDK 51, autolinking của Expo đã hỗ trợ Nitro; SDK 55 (hiện tại, 2026) tiếp tục làm mượt trải nghiệm này với expo-nitro-plugin tự động thêm namespace vào AndroidManifest và Swift bridging header.

# Thêm plugin vào app.config.ts
export default {
  expo: {
    plugins: [
      ['react-native-nitro-modules', { newArchEnabled: true }]
    ]
  }
}

# Sau đó prebuild và build development client
npx expo prebuild --clean
npx expo run:ios
npx expo run:android

Nếu bạn đang tận dụng EAS Build (xem hướng dẫn EAS Build, Submit và Update 2026), không cần thay đổi gì. EAS phát hiện Nitro tự động và bật New Architecture flag. Đội tôi đang chạy 3 module Nitro trên EAS Build M1 large với thời gian build iOS ~9 phút, Android ~6 phút.

Benchmark hiệu suất: Nitro vs TurboModules trong sản xuất

Benchmark chính thức từ Margelo (nhóm phát triển Nitro) trên iPhone 15 Pro Max cho thấy overhead một lần gọi hàm là ~1.2μs với Nitro so với ~17μs với TurboModules, chênh lệch ~14x. Con số nghe rất lớn, nhưng chỉ có ý nghĩa khi bạn gọi native hàng nghìn lần mỗi khung hình, ví dụ frame processor camera hoặc audio DSP.

Trong sản xuất, đội tôi đo trên ba workload thực tế:

  • Mã hoá AES-256-GCM 1MB: TurboModule 42ms (kèm base64), Nitro 2.8ms, nhanh gấp 15x.
  • Đọc 10.000 record SQLite qua bridge: TurboModule 380ms (JSON.stringify hai chiều), Nitro 22ms qua ArrayBuffer, cỡ 17x.
  • Realtime BLE notifications (100Hz): TurboModule bỏ frame khi CPU tải cao, Nitro giữ ổn định 100Hz với 4% CPU main thread.

Nếu bạn quan tâm tối ưu tổng thể app, tôi khuyên đọc thêm bài về tối ưu hiệu suất React Native 2026 để hiểu bức tranh lớn hơn. Nitro giúp giảm bottleneck ở lớp bridge, nhưng render tree và JS thread vẫn cần Reanimated 4 và list virtualization.

Migrate module TurboModules hiện có sang Nitro

Chi phí migrate phụ thuộc vào việc module bạn có dùng NativeEventEmitter hay không, và có phụ thuộc bên thứ ba (Reanimated, VisionCamera) hay không. Với ba module đội tôi đã port, quy trình gồm:

  1. Copy NativeCryptoSpec.ts sang HybridCrypto.nitro.ts, đổi TurboModule extend thành HybridObject.
  2. Đổi các Object generic thành TypeScript interface cụ thể; đổi mảng byte từ number[] sang ArrayBuffer.
  3. Xoá section codegenConfig trong package.json, thêm section nitro.
  4. Chạy nitro-codegen, xoá thư mục ios/generated/android/generated/ cũ.
  5. Đổi class Swift/Kotlin extend từ RCTBridgeModule/ReactContextBaseJavaModule sang HybridCryptoSpec. Xoá các @ReactMethod/@objc annotation. Nitro không cần.
  6. Với event, thay NativeEventEmitter bằng Callback trong spec (Nitro hỗ trợ callback function trực tiếp).

Case study: một module đo áp suất khí quyển (barometer) của đội tôi có ~350 dòng TurboModule. Port sang Nitro mất 4 giờ, xoá được 90 dòng boilerplate. Sau khi merge, số lỗi CI liên quan tới type mismatch giảm hẳn. Điều tôi kỳ vọng nhất từ Nitro không phải hiệu năng mà là type safety end-to-end.

Lỗi thường gặp và cách xử lý

Sau ba tháng chạy Nitro trong production, đây là top các lỗi hay gặp và cách fix:

  • "Failed to create Hybrid Object 'Crypto'": chưa đăng ký. Trên iOS, thêm HybridObjectRegistry.registerHybridObjectConstructor("Crypto") { HybridCrypto() } vào +load của module; trên Android, đăng ký trong HybridObjectRegistryPackage.kt.
  • Crash "ArrayBuffer already destroyed": bạn giữ pointer sau khi hàm return. Luôn copy: true khi cần lưu trữ.
  • Build fail "Cannot find HybridCryptoSpec": chưa chạy nitro-codegen. Thêm vào script prepare để chạy tự động sau npm install.
  • Kotlin: "Class must be abstract": bạn quên override một property/method. Codegen liệt kê đủ; kiểm tra lại .nitro.ts.
  • Promise không resolve trên Android: dùng Promise.async hoặc Promise.parallel, không tự tạo thread. Nitro có thread pool riêng.

Tài nguyên tham khảo và bước tiếp theo

Nếu muốn đi sâu hơn, tôi khuyên bắt đầu bằng tài liệu chính thức Nitro Modules, sau đó xem source của repo mrousavy/nitro trên GitHub. Đặc biệt là folder example/ có đầy đủ hybrid object, hybrid view, và benchmark suite. Với các khái niệm nền như JSI, Fabric renderer và Bridgeless mode, xem trang landing về New Architecture của React Native.

Roadmap khả thi cho đội bạn: (1) thí điểm 1 module nhỏ (analytics, storage) trong 1 sprint; (2) đo overhead trước/sau; (3) nếu OK, migrate module hot-path (camera, crypto, video); (4) rewrite Fabric views cũ sang Nitro Views. Đội tôi làm đúng lộ trình này, mất khoảng 6 tuần và không có tuần nào phải rollback.

Câu hỏi thường gặp

Nitro Modules có phải là chuẩn chính thức của React Native không?

Không, Nitro Modules là dự án cộng đồng do Margelo phát triển, không phải một phần của React Native core. Tuy nhiên nó dùng JSI công khai của Meta và hoạt động song song với TurboModules; nhiều thư viện đầu ngành (VisionCamera 4, MMKV 3, quick-crypto 1) đã chuyển sang Nitro.

Nitro Modules có yêu cầu New Architecture không?

Có, bắt buộc. Nitro dùng JSI và Bridgeless mode để đạt hiệu năng, nên bạn phải bật newArchEnabled=true trên cả iOS lẫn Android. Với dự án còn dùng Old Architecture, hãy migrate lên Fabric trước.

Hybrid Object khác gì với native module thông thường?

Hybrid Object là một class vừa "sống" trong JS vừa có phần cài đặt native tương ứng, giữ state riêng và có thể được truyền qua lại giữa JS và native mà không serialize. Native module thông thường là singleton stateless không thể trả về instance có state.

Có nên rewrite tất cả TurboModules sang Nitro ngay?

Không cần vội. Ưu tiên các module hot-path (chạy hàng chục lần mỗi giây hoặc xử lý buffer lớn) như camera, crypto, database. Với các module gọi một lần khi khởi động (config, device info), lợi ích hiệu năng không đáng kể so với chi phí migrate.

Nitro Modules có tương thích với Reanimated 4 không?

Có, hoàn toàn. Reanimated 4 dùng worklet runtime riêng nhưng vẫn tương tác được với Hybrid Object thông qua runOnJS hoặc gọi trực tiếp method sync trong worklet nếu module đã đánh dấu WorkletExecutor. VisionCamera 4 dùng chính pattern này cho frame processor.

Yelena Petrov
Về Tác Giả Yelena Petrov

React Native architect at a fintech. Builds platform teams, type-safe bridges, and runs the upgrade playbook so others don't have to.