Skip to main content

napi 0.18.0 copy "napi: ^0.18.0" to clipboard
napi: ^0.18.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. 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.

2
likes
0
points
1.09k
downloads

Publisher

unverified uploader

Weekly Downloads

Generate Dart bindings for Node-API addons and WebAssembly modules.

Repository (GitHub)
View/report issues

Topics

#wasm #node #interop

License

unknown (license)

Dependencies

analyzer, crypto, path

More

Packages that depend on napi