napi 0.19.0
napi: ^0.19.0 copied to clipboard
Generate Dart bindings for Node-API addons and WebAssembly modules.
napi #
A Dart binding compiler for native Node-API .node addons and Dart Wasm.
Declare an API in Dart, build an npm package, and import it normally:
// lib/counter.dart
import 'package:napi/napi.dart';
@NAPI()
class Counter {
int value;
Counter([this.value = 1]);
Counter.seed(this.value);
int increment([int amount = 1]) => value += amount;
}
import { Counter } from '@scope/counter';
const counter = new Counter();
counter.increment(); // 2, executed in Dart
@scope/counter is the example package built below. Imports initialize the
selected backend; consumers do not register bindings or call application main.
The compiler follows napi-rs's binding model: one Dart declaration and matching JavaScript/TypeScript APIs for native and Wasm targets. Business logic runs in Dart; generated loaders initialize the selected backend on import.
Supported bindings #
| API | Guide |
|---|---|
| Functions, optional/named arguments, defaults and strict scalar conversions | Annotations, arguments, scalars |
| Lists, Maps, dictionaries, records and value classes | Structural values, value classes |
| Classes, inheritance, object identity and generics | Classes, generic payloads, concrete aliases |
| Copied bytes, shared byte views and JS collection handles | Binary data, SharedBytes, collections |
| Futures, callbacks, streams, cancellation and resource disposal | Futures, callbacks, streams, cancellation, resources |
| Unmodified third-party Dart libraries | External selections |
The guides describe supported combinations. Unsupported signatures produce
build diagnostics. Wasm is the default target; native currently supports macOS
arm64. Dual packages expose explicit /native and /wasm entries, with the root
backend chosen at build time. There is no automatic platform selection or
fallback between backends.
Build a package #
Use Dart 3.13.5 and add the package:
dart pub add napi
Annotated sources import package:napi/napi.dart. A separate Dart VM script
builds the npm package:
// tool/build.dart
import 'dart:io';
import 'package:napi/build.dart';
Future<void> main() async {
await buildPackage(
library: File('lib/counter.dart').absolute.uri,
output: Directory('npm-package'),
packagesPath: File('.dart_tool/package_config.json').absolute.path,
metadata: {'name': '@scope/counter', 'version': '0.0.0'},
);
}
Run dart run tool/build.dart, then pack/install npm-package in the Node
consumer. Use a new output path, or follow the managed rebuild rules
for a package created by this builder on local macOS APFS or supported 64-bit
Linux filesystems.
For native, supply target: BuildTarget.native; the builder downloads and caches
the matching precompiled runtime. See native prerequisites and
explicit dual-target builds.
Use external selections for unmodified
Dart dependencies, or buildLibrary when raw artifacts are wanted.
See migration notes for the
former annotation, container and runtime assumptions.
Scalar conversions #
The same conversion rules apply to package imports on both targets. The example below uses the supported direct-Wasm path; ship its generated dependencies too.
import 'package:napi/napi.dart';
@NAPI()
String? echo(String? value) => value;
@NAPI(bigint: true)
int addWide(int left, int right) => left + right;
import { echo, addWide } from './module.wasm';
echo(null); // null
echo('🙂'); // '🙂'
addWide(1n, 2n); // 3n
Conversions never coerce input values. Required nullable parameters accept null, but not
undefined or omission. Optional parameters default for omission and undefined.
double preserves NaN, infinities and negative zero;
strings preserve UTF-16 code units, including lone surrogates. Default int
checks the JavaScript safe-integer range in both directions. The bigint option
maps all Dart int inputs/results of that function to JavaScript bigint with a
signed 64-bit input range; Dart BigInt always uses arbitrary-precision JavaScript
bigint. See the full contract, including error behavior.
Verify #
The tested toolchain is Dart 3.13.5 stable, Node 24.19.0 and 26.11.1, and TypeScript 7.0.2. The SDK adapter rejects other Dart versions because it uses experimental compiler interfaces. Native builds currently support macOS arm64; see native compatibility. Bun and browser compatibility are unverified.
See Running tests for dependencies, test commands, Node version selection and native runtime setup. See the architecture and Wasm backend design for compiler and runtime boundaries.
Relative .wasm imports use a sibling module.d.wasm.ts and TypeScript's
allowArbitraryExtensions option. A single-target Wasm package's root and
./module.wasm subpath both resolve directly to the Wasm file.
License #
MIT. See LICENSE. Generated Dart runtime helpers originate in the Dart
SDK. Generated artifacts include its license as DART_LICENSE; distributors
must retain that notice.