A highly-automated native extension framework for MoonBit and Node.js.
🇨🇳 简体中文 | 🇺🇸 English
napi-mbt is a framework inspired by napi-rs that empowers developers to build native Node.js addons using MoonBit, a fast and lightweight multi-paradigm language. napi-mbt bridges MoonBit and Node.js with a zero-overhead Node-API (N-API) C ABI, avoiding the memory cost of WASM-based marshaling while maintaining optimal execution performance.
The CLI is a standalone MoonBit native executable distributed through Mooncakes and GitHub Releases. init, generate, build, and prepublish do not invoke Node.js or npm. The Tree-sitter parser, project templates, and Node-API headers are bundled into the executable.
- ⚡ Zero Overhead Native ABI:
napi-mbtnatively connects MoonBit with Node-API without WASM intermediaries, guaranteeing bare-metal execution performance. - 🪄
#export_namegeneration: The annotation name becomes the C ABI, JavaScript, and TypeScript export name; - 📝 Automatic TypeScript Typing: Generates
.d.tsdeclaration files effortlessly alongside your MoonBit compilations for strong-typed JS/TS consumption. - 🚀 Zero-Copy Buffer Mutation: Safely manipulate Node.js Buffers directly in MoonBit memory using
NapiBufferView. - 📦 Integrated Cross-Platform CI/CD: Builds native modules and CLI binaries for Windows x64, Linux x64, and macOS ARM64. Platform packages use NPM's
optionalDependenciespattern.
Intel macOS prebuilt releases are paused because the current MoonBit toolchain installer does not support macOS x64. macOS CI and GitHub Releases target Apple Silicon (ARM64). Existing Intel package metadata is retained for compatibility.
init,generate,prepublish: the native CLI only.build: MoonBit, CMake, and GCC/Clang on Unix or Visual Studio C++ build tools on Windows. CMake must support the installed Visual Studio version.- Node.js is needed to load/test the generated addon; npm is needed to publish packages. Neither is a CLI build dependency.
Use moon install (recommended, once a release containing this entry point is on Mooncakes):
moon install unmbt/napi-mbt/cmd/napi-mbt-cli
napi-mbt-cli --helpThis installs napi-mbt-cli (napi-mbt-cli.exe on Windows) into ~/.moon/bin.
Ensure that directory is on PATH. To install the current checkout before a new
Mooncakes release, or choose ~/.unmbt as the destination:
moon install ./cmd/napi-mbt-cli
moon install ./cmd/napi-mbt-cli --bin ~/.unmbtYou can also build from source:
moon build --target native --release cmd/napi-mbt-cliThe native CLI uses moonbitlang/core/argparse for subcommands and help.
Its version comes from moon.mod: the gen_version rule and dev_build in
cmd/napi-mbt-cli/moon.pkg run scripts/gen_version.mbtx to regenerate
generated_version.mbt. Keep that generated file in releases for downstream
builds. After building the CLI, run moon run scripts/cli-native-test.mbtx to test both the release executable and moon install without Node/npm on PATH.
Or install the precompiled native CLI into ~/.unmbt (Windows uses
%USERPROFILE%\.unmbt):
On Unix-like systems the repository installer performs the same version check:
curl -fsSL https://raw.githubusercontent.com/unmbt/napi-mbt/master/scripts/install.sh | bashOn Windows PowerShell:
irm https://raw.githubusercontent.com/unmbt/napi-mbt/master/scripts/install.ps1 | iexmoon install and the Release installer provide the same standalone CLI. The old npm CLI package and Node fallback are retired. Use --generator=auto or --generator=moonbit; the old node value produces a migration error. No node_modules directory is required. Build resources are extracted into the ignored .napi-mbt/ directory.
Create a project with the native CLI on PATH:
napi-mbt-cli init my-napi-addon
cd my-napi-addon
napi-mbt-cli generate --checkThe command creates the MoonBit package, addon configuration, loaders, type declarations, and Node smoke tests. It refuses to overwrite existing files unless --force is given.
In your lib.mbt, write a function and tag it with #export_name("mbt_add"):
#export_name("mbt_add")
pub fn add(a : Int, b : Int) -> Int {
a + b
}Run the CLI tool to auto-generate bindings and build the .node binary:
napi-mbt-cli buildThis command will:
- 🔍 Parse your
#export_name("mbt_add")annotated functions. - 🛠️ Generate
napi_exports.mbtandindex.d.ts. - 🏗️ Compile the Native target (
moon build --target native). - 📦 Generate
.nodebinary atartifacts/[platform]-[arch]/.
You can now use your native addon in JavaScript:
const addon = require('./artifacts/win32-x64-msvc/napi_mbt.node');
console.log(addon.mbt_add(2, 3)); // Output: 5Set one package-wide N-API version in napi-mbt.json. The default v1 covers Node 8.6–26; Threadsafe Function requires v4 and BigInt requires v6. Core Promise APIs are v1 according to the Node-API headers.
Version releases use the repository's bump.config.json; it runs moon check before the version is committed. After all target binaries have been built, prepare platform packages and publish them in dependency order:
napi-mbt-cli prepublish
npm run publish:allUse npm run publish:dry-run to inspect package contents without publishing.
moon build --target native --release cmd/napi-mbt-cli
moon run --target native --release cmd/napi-mbt-cli -- build --release
moon run scripts/cli-native-test.mbtx
moon check --target native --warn-list +73 --deny-warn
moon test --target native
moon run scripts/parser-asan-test.mbtx
node --test scripts/test.jsThe native test stages run before Node load tests. Vendored parser versions and licenses are recorded in internal/syntax/VENDOR.md. Editable templates and header resources live in internal/assets/data/resources.json; the MoonBit resource build rule regenerates the embedded copy when that input changes.
For a detailed guide on supported types, advanced configurations, and internal architectures, refer to the documentation directories:
This project is licensed under the MIT License. See the LICENSE file for details.