Unlocking Native Performance in Node.js with Node-API (N-API)

Node.js is fast, flexible, and great for building APIs, servers, and full-stack apps. But sometimes JavaScript isn’t enough.
What if you need blazing-fast performance?
Or you want to use an existing C/C++ library instead of rewriting it in JS?
Or maybe you need access to low-level system features like file systems, drivers, or hardware?
That’s where Node-API (N-API) comes in.
1.What is Node-API (N-API)?
Node-API is a stable C API for building native addons in Node.js.
Before Node-API, addons were tied directly to V8 (Node’s JavaScript engine). Every Node.js or V8 update risked breaking your addon.
With Node-API:
Addons work across Node.js versions.
It’s engine-independent (works with V8, ChakraCore, Hermes, etc.).
It provides a stable ABI (Application Binary Interface).
2.Why Should You want N-API?
Future-proof - Your addon won’t break every time Node.js upgrades.
Performance - Run CPU-heavy tasks in native code.
Reuse existing libraries - Wrap C/C++ instead of reinventing in JS.
System access - Do things pure JS can’t (hardware, OS integration).
Popular modules that use native code:
bcrypt → password hashing
sharp → image processing
sqlite3 → database driver
3.How Node-API Works?

JavaScript talks to Node-API, which safely communicates with your C/C++ addon.
4.Let’s build a tiny addon
Let’s make our hand’s dirty by building a tiny addon
Step 1: Prerequisites
Make sure you have:
Node.js
Python (for build tools)
C++ compiler (gcc/clang/MSVC)
npm install -g node-gyp
Step 2: Addon Code (C++)
Create a new file named hello.cpp
#include <napi.h>
// This is the native C++ function that will be exposed to JavaScript.
// It takes the standard N-API CallbackInfo object and returns a Napi::Value.
Napi::Value HelloWorld(const Napi::CallbackInfo& info) {
// Napi::Env is the environment context for the current Node.js instance.
// It's used to create JavaScript values (strings, numbers, objects, etc.).
Napi::Env env = info.Env();
// Create a new JavaScript string with the value "Hello World from C++!"
// and return it. This value will be the result of calling the function
// from your Node.js code.
return Napi::String::New(env, "Hello World from C++!");
}
// The Init function is the entry point for the Node.js addon.
// It's responsible for setting up the exports that will be available
// in JavaScript when the addon is required.
Napi::Object Init(Napi::Env env, Napi::Object exports) {
// Set a property on the 'exports' object.
// The first argument is the name of the export (how you'll call it in JS).
// The second argument is a Napi::Function that wraps our native C++ function.
exports.Set(Napi::String::New(env, "hello"),
Napi::Function::New(env, HelloWorld));
// Return the modified exports object.
return exports;
}
// This macro registers the addon with Node.js.
// The first argument is the addon's name (must match 'target_name' in binding.gyp).
// The second argument is the initialization function we just defined.
NODE_API_MODULE(hello_world_addon, Init)
This is the core C++ source code. It defines the HelloWorld function that returns a string and an Init function that exports HelloWorld under the name hello.
Step 3: Build Config
Create binding.gyp
{
"targets": [
{
"target_name": "hello_world_addon",
"sources": [ "hello.cpp" ],
"include_dirs": [
"<!@(node -p "require('node-addon-api').include")"
],
"defines": [ "NAPI_DISABLE_CPP_EXCEPTIONS" ]
}
]
}
This is a build configuration file for node-gyp. It tells the compiler which C++ files to compile (sources), what to name the final binary (target_name), and where to find the necessary header files (include_dirs).
Step 4: Build the Addon
node-gyp configure build
This generates build/Release/addon.node
Step 5: Use It in Node.js
Create index.js
const addon = require('./build/Release/hello_world_addon.node');
console.log(addon.hello()); // → "Hello from Node-API!"
Run it:
node index.js
You can find the entire source code for the helloworld addon in the following Github
5.How N-API differs from Worklets or WebAssembly?

Node-API → bridge to native C++ in Node.js.
Worklets → lightweight JS workers in browser rendering.
WebAssembly → portable, high-performance modules for both browser + Node.js.
6.Node-API and Hermes
Hermes — a JavaScript engine built by Meta for React Native. It’s optimized for:
Fast startup
Low memory usage
Small binary size
Node.js usually runs on V8, but the community has experimented with running Node.js on Hermes.
Here’s why Node-API is important:
Node-API is engine-independent.
If Node.js runs on V8, ChakraCore, or Hermes, your addon still works.
Without Node-API, you’d have to rewrite bindings for every engine.
Example
Think of Node-API as a universal power adapter:
V8 = US plug
Hermes = EU plug
ChakraCore = UK plug
Without Node-API, you’d need a different charger each time. With Node-API, your addon plugs in anywhere.
7.Resources & Links
Node-API
Documentation: https://nodejs.org/api/n-api.html
Node-API bindings
Engine bindings doc: https://github.com/nodejs/abi-stable-node/blob/doc/node-api-engine-bindings.md
Node-API for Hermes
Hermes PR: https://github.com/facebook/hermes/pull/1377
Hermes Windows fork: https://github.com/microsoft/hermes-windows




