node-addon-api-cmake-addon
v1.1.0
Published
Node.js native addon using node-addon-api (C++) + CMake (no node-gyp / cmake-js)
Maintainers
Readme
node-addon-api-cmake-addon
A Node.js native addon built with node-addon-api (the C++ wrapper) and CMake only —
no node-gyp, no cmake-js, no binding.gyp.
How it works
CMakeLists.txt ← configures the addon target and loads the helper module
cmake/NodeAddon.cmake ← asks Node for header paths, sets platform linker rules
src/addon.cpp ← C++ API: Napi::Function, Napi::ObjectWrap<Counter> …
index.js ← require() the built .node from build/Shipping prebuilt binaries with npm
This repository follows the napi-rs packaging model: one root JavaScript package plus one npm package per native target.
The root package is node-addon-api-cmake-addon and declares these platform packages as optionalDependencies:
node-addon-api-cmake-addon-darwin-universalnode-addon-api-cmake-addon-win32-x64node-addon-api-cmake-addon-win32-arm64
At runtime, index.js first looks for a local binary in build/ for development, then checks generated npm/<target>/addon.node files in CI, and finally falls back to the installed platform package.
Release flow
GitHub Actions builds each target on its own runner, uploads the resulting addon.node files as workflow artifacts, tests them on matching runners, then a publish job generates npm/<target>/package.json manifests, copies the binaries into those directories, publishes the platform packages, and finally publishes the root package.
.github/workflows/changesets-release.ymlopens or updates stable release PRs formaster.github/workflows/changesets-prerelease.ymlopens or updates prerelease release PRs forrelease/next.github/workflows/publish.ymlpublishes tagged stable and prerelease releases.github/workflows/canary.ymlpublishes manual canary snapshots from CI
Versioning every release lane
This repository uses Changesets for release intent and root package versioning, while custom scripts keep the generated native packages in sync.
masteris the stable lanerelease/nextis the prerelease laneworkflow_dispatchon.github/workflows/canary.ymlpublishes a canary snapshot with npm tagcanary
Contributors add a changeset for user-facing changes with:
npm run changesetWhen a release is ready, Changesets updates package.json, then scripts/sync-release-versions.js rewrites the root optionalDependencies so every native package stays on the same version as the root package.
Stable releases
- Merge changesets into
master. - Let the release PR from
.github/workflows/changesets-release.ymlupdate versions. - Merge that release PR.
- Tag the merge commit as
vX.Y.Z. .github/workflows/publish.ymlpublishes the root package and native target packages with npm taglatest.
Prereleases
- Cherry-pick or merge release candidates into
release/next. - Enter prerelease mode once:
npm run release:pre:enter- Merge the prerelease release PR from
.github/workflows/changesets-prerelease.yml. - Tag the prerelease commit as
vX.Y.Z-next.N. .github/workflows/publish.ymlpublishes the release with npm tagnext.- Exit prerelease mode when the lane is complete:
npm run release:pre:exitCanary snapshots
Run the Canary workflow manually from GitHub Actions. It uses Changesets snapshot versioning, syncs the root optionalDependencies, prepares the generated native packages, and publishes everything with npm tag canary without requiring a git tag.
Manual package preparation
If you already have CI artifacts unpacked locally under artifacts/, assemble the publishable package directories with:
npm run prepare:npm
npm run pack:checkThis expects the following files to exist:
artifacts/darwin-universal/addon.node
artifacts/win32-x64/addon.node
artifacts/win32-arm64/addon.nodeTwo include paths
node-addon-api is a header-only C++ wrapper over N-API.
CMake must include both:
NODE_API_HEADERS_INCLUDE_DIR→node_api.hfromnode-api-headersNODE_ADDON_API_INCLUDE_DIR→napi.h,napi-inl.hfromnode-addon-api
At configure time, CMake runs node -p against the local npm packages to
discover those paths. On Windows it also reads the .def files exported by
node-api-headers and generates the import libraries needed by MSVC.
Prerequisites
| Tool | Version | |------|---------| | Node.js | 24.x LTS | | CMake | ≥ 3.15 | | C++ compiler | GCC 8+ / Clang 8+ / MSVC 2019+ |
Quick start
npm install # installs node-addon-api + node-api-headers
npm run build # cmake -S . -B build + cmake --build
npm testStep-by-step
npm install
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build --config Release
node test.jsPlatform notes
- macOS uses
-undefined dynamic_lookup, so the addon resolves Node symbols at load time. - Windows uses the
node-api-headers.deffiles to generatejs_native_api.libandnode_api.libduring CMake configure. - This setup targets plain Node.js on Windows, not Electron.
Exported API
add(a: number, b: number): number
greet(name: string): string
fibonacci(n: number): number
createPoint(x: number, y: number): { x, y, distanceFromOrigin }
class Counter {
constructor(initial?: number)
increment(step?: number): number
decrement(step?: number): number
reset(): void
readonly value: number
}N-API (C) vs Node-Addon-API (C++) — comparison
| Aspect | N-API / napi-cmake | Node-Addon-API / this project |
|---|---|---|
| API surface | C functions (napi_*) | C++ classes (Napi::*) |
| Error handling | Check napi_status manually | C++ exceptions |
| String handling | Manual buffer + length | .Utf8Value() |
| Object wrapping | Complex manual setup | Napi::ObjectWrap<T> |
| Extra dependency | None | npm i node-addon-api node-api-headers |
| ABI stability | ✓ | ✓ (thin C++ header over N-API) |
| Boilerplate | More | Less |
| Compile-time overhead | Less | Slightly more (templates) |
