C/C++ in Node.js: Creating and Using Native Addons (N-API)

- Published on

Native addons let you extend Node.js with C/C++ for performance or to access OS/third‑party libraries. This guide shows how to create a minimal addon using N‑API (stable ABI) and the node-addon-api
C++ wrapper, with all code written out (no screenshots).
Why N‑API?
N‑API provides a stable ABI across Node.js versions, reducing rebuild pain. The C++ convenience wrapper node-addon-api
gives a friendly API on top of N‑API C.
1) Project Setup
mkdir cpp-addon && cd cpp-addon
npm init -y
npm i node-addon-api
npm i -D node-gyp
Add scripts to package.json
(optional but handy):
{
"scripts": {
"build": "node-gyp rebuild",
"rebuild": "node-gyp configure build",
"start": "node index.js"
}
}
2) binding.gyp
Create binding.gyp
in the project root:
{
"targets": [
{
"target_name": "addon",
"sources": ["src/addon.cc"],
"include_dirs": [
"<!(node -p \"require('node-addon-api').include\")"
],
"defines": ["NAPI_DISABLE_CPP_EXCEPTIONS"],
"conditions": [
["OS=='mac'", { "xcode_settings": { "OTHER_CPLUSPLUSFLAGS": ["-std=c++17"] } }],
["OS=='linux' or OS=='freebsd'", { "cflags_cc": ["-std=c++17"] }],
["OS=='win'", { "msvs_settings": { "VCCLCompilerTool": { "AdditionalOptions": ["/std:c++17"] } } }]
]
}
]
}
3) Addon Source (C++)
Create src/addon.cc
:
#include <napi.h>
// add(a, b): returns a + b with basic argument validation
Napi::Value Add(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
if (info.Length() < 2 || !info[0].IsNumber() || !info[1].IsNumber()) {
Napi::TypeError::New(env, "Expected two numbers").ThrowAsJavaScriptException();
return env.Null();
}
double a = info[0].As<Napi::Number>().DoubleValue();
double b = info[1].As<Napi::Number>().DoubleValue();
return Napi::Number::New(env, a + b);
}
// exports.add = Add
Napi::Object Init(Napi::Env env, Napi::Object exports) {
exports.Set(Napi::String::New(env, "add"), Napi::Function::New(env, Add));
return exports;
}
NODE_API_MODULE(addon, Init)
Notes:
- We disable C++ exceptions (
NAPI_DISABLE_CPP_EXCEPTIONS
) inbinding.gyp
to keep the binary smaller and rely on Node‑style error reporting.
4) Build the Addon
npx node-gyp configure build
The compiled module will be at ./build/Release/addon.node
.
5) Use the Addon from JavaScript
Create index.js
in the project root:
// Option A (direct path):
const addon = require('./build/Release/addon.node')
// Option B (via "bindings" helper):
// const addon = require('bindings')('addon')
console.log('2 + 3 =', addon.add(2, 3))
Run:
node index.js
Expected output:
2 + 3 = 5
6) TypeScript (Optional)
If you want TS types, add a minimal declaration file index.d.ts
:
export function add(a: number, b: number): number
Then update package.json
:
{
"types": "index.d.ts"
}
7) Common Issues
- Ensure native toolchain is installed (macOS: Xcode CLT; Linux: build‑essential; Windows: Visual Studio Build Tools).
- If Node.js version changes,
node-gyp rebuild
may be needed. - Prefer N‑API over legacy NAN for ABI stability across Node versions.
Where to Go Next
- Wrap existing C/C++ libraries and expose functions/classes to JS
- Pass Buffers to C++ for high‑throughput compute and I/O
- Explore
Napi::ObjectWrap
to create C++ classes exposed as JS objects
With N‑API, you can ship fast, portable native extensions that keep working across Node.js upgrades.