Cross-compiling
Contents
- Output layout
- What every release build does
- Building a subset
- What
index.jsis for - Default platforms
- Custom platforms
- Electron and other hosts
- Optimization
That single command builds your addon for every platform listed in .npm.platforms and lays out the npm package structure ready to publish. Zig's cross-compilation is built in: there are no toolchains to install, no Docker images, no QEMU.
The same command is also safe to run repeatedly. The build owns and reconciles the files it generates; anything you've added or edited (your seam over the addon, user fields on the main package.json, the version, files unrelated to the build) is preserved.
Output layout
The first napikit build --release writes a complete npm/ tree:
<name> is your addon's name. <scope> is the npm scope from the .scope field of the .npm block in build.zig. Every per-platform binding lives under that scope.
Calling addLib more than once in build.zig is supported; each addon gets its own npm/<name>/ subtree and is reconciled independently. See Multiple addons in one repo.
What every release build does
napikit build --release is the only command you need during release. It cross-compiles, then reconciles npm/ against the policy in build.zig. Re-run it as often as you like; you cannot drift npm/ out of sync with build.zig.
The reconciler is conservative about your work:
The practical guarantee: edit build.zig, then re-run napikit build --release. That works for every change, including renaming the scope, adding or removing platforms, changing .dts, and renaming .host_exe. You do not need to delete npm/ first; the reconciler removes a disabled build-owned declaration and otherwise preserves unrelated user files.
The one exception is renaming the addon's .name itself. The new tree is created fresh under npm/<new-name>/, the old npm/<old-name>/ becomes an orphan, and the build prints a warning that asks you to copy any user fields you want to keep on the new main package.json and delete the old folder. (Renaming a published npm package is a rare and disruptive event; this is intentional.)
Building a subset
A full release build cross-compiles every platform for every addon. During local development you often want something faster.
--current builds only the host platform's binding:
This compiles a single .node for the machine you are on and skips the others. The main package.json still lists every platform in optionalDependencies, and the build is additive: bindings already in npm/ from a previous full build are left in place, not deleted. Run a full napikit build --release before publishing so every platform is present.
--only narrows the build to specific addons by .name, useful when build.zig calls addLib more than once:
Unlisted addons are skipped entirely and their npm/ subtrees are left untouched. Combine the two flags to rebuild just one addon for just your platform:
What index.js is for
binding.js is fully owned by the build. It implements platform detection and loads the matching <scope>/binding-… package. Do not edit it; your changes will be overwritten on the next build.
index.js is your seam. The default napikit build --release writes is a plain re-export:
That is already a working entry point. Keep it as-is, or use it for JS-side wrapping, normalization, or higher-level helpers. Edits to index.js survive every rebuild.
Default platforms
If .platforms is omitted from .npm, you get this set:
That is 11 binaries from one napikit build --release call.
Custom platforms
Override the default list to ship only what you need:
Adding or removing entries from .platforms is a regular edit. The next napikit build --release adds bindings for the new entries and deletes bindings for ones you took out. The full list of Platform values is in build.zig (addLib).
The Zig enum uses names such as .macos_arm64 and .windows_x64; generated npm binding suffixes still use Node/npm platform names such as darwin-arm64 and win32-x64.
Electron and other hosts
By default, addons are compiled to load into node.exe on Windows. To target Electron, set .host_exe:
This only affects Windows import-library generation. On macOS and Linux the addon loads into whatever process imports it without any host-specific configuration.
Optimization
napikit build --release uses ReleaseFast for every cross-compiled binary. For development, napikit build uses whatever -Doptimize you specify (default Debug). Override the release mode with: