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
CTO
@
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.

Table of contents
Facing complex cross-platform challenges?

We help deliver consistent experiences across platforms with one codebase.

Let’s chat
Link copied to clipboard!
//
Insights

Learn more about

Cross-Platform

Here's everything we published recently on this topic.

Sort
//
Cross-Platform

We can help you move
it forward!

At Callstack, we work with companies big and small, pushing React Native everyday.

Code Sharing

Implement effective code-sharing strategies across all platforms to accelerate shipping and reduce code duplication.

Migration to React Native

Plan and execute a migration from native or hybrid stacks to React Native with minimal disruption and clear technical direction.

Desktop App Development

Develop powerful cross-platform desktop applications that work across Linux, Windows and Mac.

Web App Development

Build a solid foundation that meets latest standards and scales easily to other platforms in the future.