Node-Addon-API C++ Wrapper for Node.js Native Addons
Node-Addon-API (N-API) is a C++ wrapper library that significantly simplifies the development of Node.js native add-ons. It provides a higher-level, more idiomatic C++ interface over the raw C-based Node-API, leveraging modern C++ features like RAII (Resource Acquisition Is Initialization) and exceptions for safer and more robust native module development. This abstraction layer helps manage memory and resources automatically, reducing common errors associated with manual memory management in C. The current stable version is 8.7.0, with minor feature and bugfix releases occurring every few months. Its primary differentiator is making Node.js native module development accessible to C++ developers by providing familiar C++ paradigms, while maintaining ABI stability across Node.js major versions, ensuring compiled add-ons continue to work without recompilation against newer Node.js releases. It is the recommended path for new native addon development.
Common errors
-
fatal error: 'napi.h' file not found
cause The C++ compiler cannot locate the `node-addon-api` header files, meaning the include paths are incorrect or missing in your build configuration.fixEnsure your `binding.gyp` includes `"<!@(node -p \"require('node-addon-api').include\")"` in the `include_dirs` array. For CMake, ensure you correctly `find_package(node_addon_api CONFIG REQUIRED)` and link against `node_addon_api::node_addon_api`. -
Error: The specified module could not be found. (on Windows) or Error: libmyaddon.node: undefined symbol: some_napi_function (on Linux/macOS)
cause The native addon `.node` file could not be loaded due to a missing dependency (e.g., a shared library your addon links against) or a linker error during compilation that resulted in an unusable `.node` file.fixCheck your `binding.gyp` for correct `libraries` and `link_settings` entries. Run `node-gyp rebuild` with increased verbosity (`--verbose`) to inspect linker output. On Linux, use `ldd build/Release/myaddon.node` to identify missing shared library dependencies. -
Node.js crashes with a segmentation fault or unhandled C++ exception when calling a native method.
cause This often indicates an unhandled C++ exception propagating out of the native code, incorrect memory access (e.g., dangling pointers), or an ABI incompatibility. It can also happen if `NAPI_CPP_EXCEPTIONS` is not defined but C++ exceptions are being used.fixEnsure `NAPI_CPP_EXCEPTIONS` is defined in your build configuration. Wrap potentially throwing C++ code in `try-catch` blocks within your `Napi::CallbackInfo` handlers to convert C++ exceptions into JavaScript exceptions using `Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();`. -
TypeError: addon.myFunction is not a function
cause The native addon loaded successfully, but the JavaScript environment cannot find the expected function. This means the C++ `Init` function did not correctly expose the function on the `exports` object or exposed it with a different name.fixDouble-check the `Init` function in your C++ code. Ensure `exports.Set(Napi::String::New(env, "myFunction"), Napi::Function::New(env, MyFunctionMethod));` correctly exposes the function with the intended JavaScript name ('myFunction' in this example).
Warnings
- gotcha Node-API provides ABI stability for its underlying C interface, meaning compiled addons typically work across Node.js major versions without recompilation. However, `node-addon-api` is a C++ wrapper; its C++ API can evolve, and major version bumps (e.g., v7 to v8) may introduce C++ API changes requiring code updates and recompilation.
- breaking Addons built with `node-addon-api` require specific Node.js versions as indicated by the `engines.node` field in the package.json (currently `^18 || ^20 || >= 21`). Building or running on unsupported Node.js versions can lead to build failures or runtime crashes due to incompatible N-API versions or internal changes.
- gotcha Node-Addon-API heavily utilizes C++ exceptions for error handling. It is critical to define `NAPI_CPP_EXCEPTIONS` in your `binding.gyp` (or equivalent build system) and ensure your compiler is configured to handle C++ exceptions. Failing to do so can lead to unexpected crashes, segmentation faults, or silent failures when exceptions are thrown from native code.
- gotcha While RAII is leveraged for many resources, developers must explicitly manage persistent references to JavaScript objects (`Napi::Persistent<T>`) that need to outlive the scope of a single N-API call to prevent them from being garbage collected prematurely by the V8 engine. Forgetting to manage these can lead to use-after-free bugs or incorrect behavior.
- gotcha Using `Napi::ThreadSafeFunction` (TSFN) for asynchronous operations across threads introduces significant complexity. Incorrect usage, particularly around managing `ref()` and `unref()` calls, lifetime management of the `ThreadSafeFunction` object, and proper data transfer between threads, is a common source of deadlocks, memory leaks, or application crashes.
Install
-
npm install node-addon-api -
yarn add node-addon-api -
pnpm add node-addon-api
Imports
- myAddon
import { myAddon } from 'node-addon-api';const myAddon = require('./build/Release/myaddon.node'); - myAddon
const myAddon = require('node-addon-api');import myAddon from './build/Release/myaddon.node';
- loadNativeAddon
import { createRequire } from 'module'; const require = createRequire(import.meta.url); const myAddon = require('./build/Release/myaddon.node');
Quickstart
/* C++ source file: hello.cc */
#include <napi.h>
// Simple synchronous method that returns a string
Napi::String Method(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
return Napi::String::New(env, "world");
}
// Initialize the addon
Napi::Object Init(Napi::Env env, Napi::Object exports) {
exports.Set(Napi::String::New(env, "hello"),
Napi::Function::New(env, Method));
return exports;
}
// Register the addon module
NODE_API_MODULE(hello, Init)
/* binding.gyp (build configuration for node-gyp) */
{
"targets": [
{
"target_name": "hello",
"sources": [ "hello.cc" ],
"include_dirs": [
"<!@(node -p \"require('node-addon-api').include\")"
],
"cflags!": [ "-fno-exceptions" ],
"cflags_cc!": [ "-fno-exceptions" ],
"defines": [ "NAPI_CPP_EXCEPTIONS" ],
"libraries": []
}
]
}
/* JavaScript usage: index.js */
// To build the addon: run `node-gyp rebuild` in your terminal.
// This will create a `build/Release/hello.node` file.
const addon = require('./build/Release/hello.node');
console.log('addon.hello() =', addon.hello()); // Expected output: addon.hello() = world