A high-performance showcase of Nitro Modules, the next generation of native modules for React Native. This project demonstrates how to build type-safe, synchronous, and zero-overhead native integrations using the JavaScript Interface (JSI).
Nitro Modules (developed by Marc Rousavy) represent the evolution beyond TurboModules. They eliminate the bridge overhead entirely by allowing JavaScript to call into native code (C++, Swift, Kotlin) with zero serialization.
- Direct JSI Calls: Zero-overhead communication between JS and Native.
- Type Safety: Automatic code generation (Nitrogen) from TypeScript specs.
- Modern Languages: First-class support for Swift 5.9+ and Kotlin.
- Synchronous Operations: Call native methods directly in the JS thread.
- Complex Data Support: Seamless conversion of Objects, Arrays, and Enums.
This demo goes beyond a simple setup. It implementats industry-standard architectural patterns for production-ready apps:
- Logic Isolation: All business logic and state management are extracted into custom hooks (see
src/screens/hooks/useNitroDemo.ts). - Atomic Components: The main screen is decomposed into small, focused sub-components (see
src/screens/components/) for better readability and maintainability. - Style Isolation: Styles are kept in separate
.styles.tsfiles, following the project's strict design mandates.
- Zero
anyUsage: The entire module is 100% type-safe. We use proper generics and inheritance to satisfy theHybridObject<{}>constraint in the latestreact-native-nitro-moduleswithout resorting toany. - Enum Mapping: Demonstrated how to handle numeric enums required by C++ JSI while maintaining friendly labels in the UI.
- Standardized
nitro.json: Configured with correct namespaces, module names, and Autolinking records. - Modern Safe Areas: Replaced deprecated
SafeAreaViewwithreact-native-safe-area-contextto ensure consistent UI across all modern mobile devices.
src/specs/: TypeScript Specifications (.nitro.ts). The source of truth for your modules.src/modules/: JS Entry Points. Clean, type-safe access to native modules.src/screens/: UI Components showcasing the modules using modular patterns.src/screens/hooks/: Custom hooks isolating native integration logic.ios/NitroModulesDemo/: Swift Implementations.android/app/src/main/java/com/margelo/nitro/nitromodulesdemo/: Kotlin Implementations (using standardized packages).nitro.json: Configuration for Nitrogen and Autolinking.
cd NitroModulesDemo
npm installNitro uses Nitrogen to generate native protocols (Swift) and abstract classes (Kotlin).
npm run nitro-codegenNitrogen produces a collection of C++, Swift, and Kotlin files in the nitrogen/generated/ directory. These are ephemeral "glue code" files that bridge the gap between JavaScript and your native implementations.
⚠️ MODIFICATION RULE: Generally, you should NEVER modify files innitrogen/generated/. They are overwritten every time you runnitro-codegen.- Did I touch them?: YES. Due to the specific nested structure of this repository, Nitrogen 0.35.2 generated paths and access levels that were incompatible with the standalone Android build. I have applied the following Surgical Fixes to the generated files:
- Fixed Gradle Paths: In
NitroModulesDemo+autolinking.gradle, I corrected the source directory depth from../to../../. - Fixed CMake Paths: In
NitroModulesDemo+autolinking.cmake, I converted relative Nitrogen paths to absolute paths using${CMAKE_CURRENT_SOURCE_DIR}to prevent "File not found" errors during C++ compilation. - Exposed Loader: In
NitroModulesDemoOnLoad.kt, I changed the class frominternaltopublicso it could be initialized from theMainApplication.
- Fixed Gradle Paths: In
Note for Developers: If you re-run npm run nitro-codegen, you may need to re-apply these depth fixes (../ -> ../../) in the generated files until Nitrogen provides better support for standalone nested projects.
- iOS:
cd ios && bundle exec pod install
- Android:
- Sync your project with Gradle files in Android Studio.
- The build pipeline is already pre-configured to handle Nitrogen outputs.
To ensure a seamless developer experience without touching generated files, I have implemented the following production-ready build pipeline:
- Gradle Integration: Added
apply from: "../../nitrogen/generated/android/NitroModulesDemo+autolinking.gradle"toapp/build.gradleto automatically link Nitrogen's logic. - Source Mapping: Configured
sourceSetsinbuild.gradleto point the Kotlin compiler to${project.projectDir}/../../nitrogen/generated/android/kotlin, ensuring your implementations can always find their base specs. - C++ JSI Pipeline (CMake): Created a modern CMake build system in
android/app/src/main/jni/CMakeLists.txt. This compiles Nitrogen's C++ wrappers into a high-performance shared library (libNitroModulesDemo.so). - Native Initialization: Updated
MainApplication.ktto callNitroModulesDemoOnLoad.initializeNative(). This ensures the JSI bindings are registered immediately when the app starts. - 16KB Page Size Support: Added specific linker flags to
CMakeLists.txtto ensure the native library is compatible with Android 15+ emulators and devices that use 16KB memory pages.
npm run androidnpm run ios- Define Spec: Open
src/specs/MathModule.nitro.ts. - Generate: Run
npm run nitro-codegen. - Implement:
- Swift:
ios/NitroModulesDemo/MathModule.swift - Kotlin:
android/app/src/main/java/com/margelo/nitro/nitromodulesdemo/MathModule.kt
- Swift:
- Use: Check
src/modules/MathModule.tsfor instantiation andsrc/screens/hooks/useNitroDemo.tsfor usage.
Part of the React Native Reference & Learning Hub