How Node-API Works in React Native: A Deep Dive

Authors
Kræn Hansen
Software Engineer
@
MongoDB
Jamie Birch
Engineer
@
Scoville, NativeScript TSC
Mike Grabowski
CEO & Founder
@
Callstack

A few weeks back, we introduced our work on bringing Node-API support to React Native and why we believe it will benefit our community. With this article, we want to dive deep into what Node-API actually is and how we're bringing it to React Native.

How it all works together

As mentioned above, Node-API is an ABI-stable JS engine/runtime abstraction, built and maintained by the Node.js project governed by the OpenJS Foundation. In practice it’s a couple of C header files declaring the types and functions expected by a Node-API addon, to be implemented by a Node-API host, such as Node.js

We (and the Node.js docs) use the terms: Node-API module, Node-API addon and addon often interchangeably. In practice, they’re the same thing: A dynamic library expecting and calling into Node-API functions.

When a Node-API addon build is cached so that users don’t need to recompile it from source code, it’s colloquially referred to as a “pre-build”.

Host package

At the core of everything is the react-native-node-api package. We refer to it as “the host” because it sets up the environment needed for a Node-API addon to register itself in a React Native app before it’s required in JavaScript.

Bundling addons

Before an addon can register itself, it must be included in the app bundle. This is different from Node.js, where the dynamic .node file just needs to be present on the filesystem.

In React Native, we bundle the addon by scanning the app and its dependencies for directories and files that match a specific format. We then copy them into the host package and rename them to avoid conflicts. This process is called linking or auto-linking, and it happens during every app build—via CocoaPods, Xcode build phases, and/or Gradle scripts—to ensure native code changes are applied.

Loading

In React Native, TurboModules are loaded using TurboModuleRegistry.getEnforcing. Node-API modules are loaded using the requireNodeAddon function provided by the host:

requireNodeAddon("./my-addon")

To support existing Node-API modules, we provide a Babel plugin that transforms .node file imports into requireNodeAddon calls:

const addon = require('./my-addon.node');

Just require the prebuilt file using a relative path and the addon will load and initialize at runtime.

Providing the Node-API Functions to Addons

Node-API addons expect the host to implement the Node-API functions. Some of these are engine-specific (e.g., object creation, property access), while others are runtime-specific (e.g., async task scheduling, addon registration).

The engine-specific functions are provided by Hermes while the remaining runtime-specific functions are provided by the host. You can follow the status of Hermes-specific work by visiting this PR.

In Node.js, the runtime provides the functions directly, and addons link against the Node.js binary. In React Native, we provide a lightweight dynamic library called weak-node-api. It exposes Node-API functions and allows both Hermes and the host package to register their respective function implementations.

Build tools

To support existing Node-API addons and improve developer experience, we also published CLI tools:

  • cmake-rn functions similarly to cmake-js for Node.js. It acts as a wrapper around the CMake build system, injecting header and library paths for Node-API libraries. This facilitates building and producing the Node-API addon for Android and Apple platforms.
  • gyp-to-cmake makes it simple to convert any package relying on the GYP build system (through node-gyp) to a CMake project, by transforming the binding.gyp file into a CMakeLists.txt file. Combined with cmake-rn, it allows you to build hundreds (thousands?) of existing GYP-based packages to use in React Native too.
  • ferric-cli wraps the napi.rs CLI to generate end-to-end type-safe Node-API bindings in the Node-API addon format from macro-annotated Rust code. Learn more about Ferric in Kræn's talk at React Summit '25.

Get Involved

We’re building toward a future where native modules in React Native are easier to author, share, and maintain across frontend, backend and multiple different cross-platform frameworks, powered by Node-API. If that vision excites you, we’d love your help.

You can find the full codebase, docs, and examples on GitHub.

Here’s how you can join in:

  • Try it out – Add a Node-API module to your app or build your own.
  • Contribute – Check out good first issues, submit improvements, or test on real-world projects.
  • Spread the word – Star the repo, share your experience, or help others discover what’s possible.

We’re here to support you and we’re excited to see what you build.

Insights

Learn more about Cross-Platform

cover

Feb 27Article

Sparkling: The Missing App Layer for Lynx.js?

A hands-on look at Sparkling for Lynx.js: CLI, native navigation, and the tooling layer that turns Lynx into a full mobile app framework.

cover

Feb 12Live Stream

Sparkling: A New Framework for Lynx

Join the Lynx team live as we explore Sparkling, its boundaries with Lynx, core features, and bootstrap a project from scratch.

cover

Dec 19Article

Visualizing the Dual-Thread Model of Lynx JS

A practical look at Lynx JS’s dual-thread runtime, using real examples to show how main and background threads behave under load.

cover

Dec 2Live Stream

Two Threads of Lynx.js Part 2

Learn how Lynx.js uses a dual-threaded model, how its APIs work, and what it means for performance in this live session with Lukasz Chludzinski and Kewin Wereszczynski.

cover

Nov 27Live Stream

Exploring Lynx.js and Its Two-Thread Runtime

A recap of our live session exploring how Lynx.js splits work across a main thread and a background thread.

cover

Nov 7Article

Exploring Lynx JS: From Quick Start to CLI Workflows

Learn how to set up Lynx JS, explore its ecosystem, and use the Community CLI to build native apps with a familiar JavaScript workflow.

cover

Sep 19Podcast

React Native at Scale With NFL

Discover how the NFL uses React Native, Expo, and a monorepo to ship apps across iOS, Android, web, and TV with one stack.

cover

Feb 7Article

Bringing WebAssembly to React Native With Polygen

Discover Polygen, a toolkit that brings WebAssembly to React Native, compiling WASM to C for near-native performance with no runtime overhead.

cover

Dec 20Article

From Native to Multiplatform Development: Unpacking Kotlin and Compose

Discover how Kotlin Multiplatform, Jetpack Compose, and Compose Multiplatform compare to React Native. Learn their roles, relationships, and use cases.

cover

Dec 3Article

Aiming for Success in the TV App Development Space With React Native

Learn how to handle platform differences, optimize user interactions, and balance standardization with customization when building a React Native app for TV.

cover

Aug 7Podcast

Open Mobile Hub: Non-GMS and Cross-Platform Possibilities

When you build applications, do you ever consider users who may not have access to Google Mobile Services? They may not be your target audience now, but it's good to be aware of what options you have in store for non-GMS devices — which is exactly what we're talking about in this episode!

cover

May 31Podcast

Stepping Into New Dimension With React Native VisionOS

Try immersing yourself in the React Universe with React Native visionOS! Listen about the latest changes in the framework & watch a 3D app demo.

cover

Mar 19Tutorial

The Hard Way vs. The React Native AI SDK Way: Stop Writing Custom Modules for Every Model

Learn how React Native AI uses a unified provider model to switch between cloud and on-device LLMs without rewriting application logic, enabling reliable AI experiences online and offline.

cover

Mar 12Tutorial

Build Smarter Apps: Tool Calling & AI Orchestration Explained

Learn how on-device models in React Native can call tools, interact with external APIs, and return structured outputs you can use directly in application logic.

cover

Mar 5Tutorial

MLC LLM + React Native: On-Device AI Without the Pain

Learn how to run third-party on-device LLMs in React Native using MLC LLM. Choose your models, run them efficiently across platforms, and keep a unified JavaScript API with React Native AI.

cover

Feb 24Tutorial

Intelligent Fallbacks with Apple Intelligence in React Native

Learn how to use Apple’s built-in Foundation Models in React Native apps, reduce memory usage, and enable fast, fully on-device AI with React Native AI Apple.

cover

Feb 10Tutorial

What Is the React Native AI SDK? A Complete Intro & Quickstart

Learn why on-device AI matters for React Native apps, how local LLMs behave offline, and what problems React Native AI is designed to solve from day one.

cover

Jan 29Tutorial

Implementing an Android TurboModule with Kotlin

Learn how to implement a React Native TurboModule on Android, from the TypeScript spec and Codegen to the Kotlin implementation and package registration.

cover

Jan 19Tutorial

Working with Different Threads in Swift TurboModules

Learn how JavaScript, native module, background, and main threads interact in React Native TurboModules, and how to use GCD queues to run async work safely in Swift.

cover

Jan 9Tutorial

How to Add Type-Safe Constants to Swift TurboModules

Learn how to expose typed, immutable constants from a Swift TurboModule using Codegen, and get full end-to-end type safety between native and JavaScript.

cover

Dec 30Tutorial

Adding Event Emitters to Your TurboModule in Swift

Learn how to emit native events from a Swift TurboModule and subscribe to them in JavaScript, including proper memory management and Codegen integration.

cover

Dec 22Tutorial

Writing Your First TurboModule in Swift

Learn how to build a fully working TurboModule in Swift, integrate it with Codegen, and bridge it through Objective‑C inside an Expo app.