Build and packaging
build.zig exposes the consumer build API. Its public surface includes Platform, Import, Dts, NpmConfig, LibOptions, and addLib.
Build behavior
addLibbuilds a host.nodeaddon.-Dnpm=trueenables release package generation and cross-compilation.-Dnpm-host=truerestricts native compilation to the host platform and fails if that platform is absent from.npm.platforms.-Dnpm-only=name-a,name-bfilters addons in multi-addon projects.Dts.none,Dts.file, andDts.autocontrol declaration output.Dts.noneomits bothtypesandindex.d.tsfrom the generated main manifest. When a release package switches to.none, reconciliation removes an ownership-marked build declaration and its managedfilesentry while preserving arbitrary handwritten declarations and unrelated user files.- Generated main and binding manifests refresh the configured license and enforce public npmjs
publishConfig; existing user metadata cannot drift either policy. Binding packages are fully generated: their repository mirrors the final main manifest, stale lifecycle or unknown fields are removed, and only the canonical native entry remains. - The selected release optimization mode is propagated to every cross-compiled module and binary.
- Release configuration rejects non-portable package names, malformed repository metadata, duplicate addon names, and colliding binding package identities before compilation writes release output.
- A fresh addon's generated main and binding packages inherit the unique strict version shared by existing generated, binding, and extra packages. The first publishable package starts at
0.0.0; invalid or drifting existing versions fail before Zig. - Development builds emit export-aware CommonJS and ESM wrapper sources from the same Zig declaration walk and optimization mode as the native addon and release metadata;
napikitselects the root wrapper frompackage.json.type, migrates only canonical generated content, and preserves custom loaders. - Export-aware development wrapper metadata is generated only for host artifacts. Explicit cross-target builds remain target-only and do not force a second host compilation of user source.
- Linux loaders use the Node diagnostic report. If libc cannot be identified, they try both GNU and musl variants through local and installed-package paths before reporting the aggregate failure.
- Release reconciliation validates every generated source as a real directory or regular file, rejects symlinks and non-canonical manifests, and verifies matching main/binding license and repository provenance, the npmjs/public publication policy, plus target-specific
os,cpu, andlibcmetadata before touchingnpm/. - Package synchronization copies from a fingerprint-verified source snapshot and stages changes transactionally. It refuses to take over a standalone, corrupted, or differently named package at a generated addon path. Commit uses an exclusive destination-directory claim and no-overwrite entry creation; cleanup moves entries through randomized recovery claims and removes only identity- and content-verified transaction data. It aborts if another process changes the source, destination, temporary tree, or recovery backup, and preserves recovery data when rollback cannot proceed safely.
- One project lock covers release version preflight, shared
zig-out/npmcleanup, Zig execution, and reconciliation. A secondnapikit build --releasefails before touching shared output; an abandoned lock is reclaimed only when its recorded process is gone and its bytes and identity are unchanged.
Boundaries
- Keep generated package names, binary suffixes, binding paths, optional dependencies, and npm manifest fields compatible.
- Keep npmjs as the public registry and preserve public access.
- Treat linker flags, Windows import libraries, target lists, and generated manifests as release-critical.
- Test build graph changes with the fixture projects and CLI release tests, not only the repository's own build.
Relevant tests live in tests/cli/build-dev.test.ts, tests/cli/build-release.test.ts, tests/fixture-cli/, and tests/fixture-lib/.
Internal structure
- Keep
build.zigas the public facade foraddLib,Platform,Import,Dts,NpmConfig, andLibOptions. - Keep target definitions and npm suffix mapping in
build/targets.zig. - Keep OS-specific link configuration in
build/linker.zig. - Keep escaped npm manifest and loader rendering in
build/npm_manifest.zig. - Keep declaration and local entry generation in the existing
build/*_emit.zigmodules. - Keep development output snapshot, CAS, and recovery mechanics in
packages/cli/src/build/dev-outputs.ts; command entry code should orchestrate them rather than reimplement filesystem transactions.
These modules are implementation details. Moving work between them must not change the public build.zig API, generated package names, or output layout.
Use the detailed build API, TypeScript declaration, cross-compiling, and publishing pages when changing their user-visible behavior.