Skip to content
Development
Agent

nodejs

<!-- GENERATED from docs/playbooks/integration/nodejs.md by scripts/build-agent-skill.mjs. Do not edit. -->

BOOST
From plugin
crossbind
14832 skills32 agents
Install
$ npx -y skills add crossbind/crossbind --agent claude-code

How it fires

How this agent gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.

Context preview

The summary Claude sees to decide when to auto-load this agent.

<!-- GENERATED from docs/playbooks/integration/nodejs.md by scripts/build-agent-skill.mjs. Do not edit. -->

Agent definition

nodejs.md

<!-- GENERATED from docs/playbooks/integration/nodejs.md by scripts/build-agent-skill.mjs. Do not edit. -->

Integration — Node.js (no bundler)

> Persona 2 sub-playbook. The user's project is a plain Node.js application or library — no Vite, Webpack, Rollup, RN, etc. Detection: crossbind build script targets `-e node`, or the project's `package.json` declares `main`/`module`/`bin` without bundler deps.

Goal

Build crossbind artifacts for the Node runtime (`-e node`) and `require`/`import` the loader from any Node script. No bundler integration; the build is invoked directly via `crossbind build`.

When to use

  • Backend service, CLI, script, or Node-native library.
  • No browser, no React Native, no edge runtime.
  • Multithread (`runtime: 'mt'`) is supported via Node's `worker_threads` on the supported Node 24+ runtime.

Files involved

| File | Role | |------|------| | `package.json` | + `crossbind`, optional `@crossbind/port-<name>`; declare a `build` script that runs `crossbind build -e node` | | `crossbind.config.{js,mjs}` *(new at root)* | Project-level crossbind config (deps to consume, paths) | | `src/native/` *(if user wraps own C++)* | `.h` + `.cpp` source | | `<entry>.js` (e.g. `index.js`) | `require`/`import` the built loader | | `dist/<name>-<target>.node.{js,wasm}` | Build output |

Commands

pnpm add -D crossbind@beta
pnpm add @crossbind/port-<name>@beta     # optional

# Single-thread build
pnpm crossbind build -p wasm -a wasm32 -r st -e node -b release

# Multithread build (Node worker_threads)
pnpm crossbind build -p wasm -a wasm32 -r mt -e node -b release

# Run
node index.js

Reference setup

Mirror `examples/backend-nodejs-wasm/` (single-thread) or `e2e/backend-nodejs-multithread/` (multithread).

`package.json`:

{
  "scripts": {
    "build": "crossbind build -p wasm -a wasm32 -r st -e node -b release",
    "start": "node src/index.js"
  },
  "dependencies": {
    "@crossbind/port-<name>": "^x.y.z"
  },
  "devDependencies": {
    "crossbind": "^2.0.0"
  }
}

`crossbind.config.mjs`:

// If consuming prebuilt packages:
import Matrix from '@crossbind/example-lib-prebuilt-matrix/crossbind.config.js';

export default {
    general: { name: 'my-node-service' },
    dependencies: [
        Matrix,
    ],
    paths: {
        config: import.meta.url,
        output: 'dist',
    },
};

Entry script `src/index.js` (CommonJS):

const initNative = require('../dist/my-node-service-wasm-wasm32-st-release.node.js');

initNative().then(({ Native }) => {
    console.log(`Result: ${Native.sample()}`);
});

ESM equivalent:

import initNative from './dist/my-node-service-wasm-wasm32-st-release.node.js';

const { Native } = await initNative();
console.log(`Result: ${Native.sample()}`);

The exact output filename is `<general.name>-<target.path>.<runtimeEnv>.{js,wasm}`. For st-release: `<name>-wasm-wasm32-st-release.node.js`. For mt-release: `<name>-wasm-wasm32-mt-release.node.js`.

The st-release build also writes `dist/node/wasm.mjs` and its `.d.mts`: one ES module that exports every bound class, function and constant, filled when `initNative()` resolves, so init options still reach the runtime:

import { initNative, Native } from './dist/node/wasm.mjs';

await initNative();
console.log(`Result: ${Native.sample()}`);

A library publishes that module under a path of its own, as `@crossbind/example-lib-prebuilt-matrix/node/wasm` does. The loader is CommonJS with a `.js` extension, so the build writes `dist/package.json` with `"type": "commonjs"` when the output directory has none; it keeps loading as CommonJS inside a `"type": "module"` package.

Importing headers and Rust directly

A Node.js app can import its native code the way a bundler app does: its own header, a package's header, a `conan:` header, a `.rs` file or a `cargo:` crate.

import { initNative, Native, NATIVE_ANSWER } from './native/native.h';
import { Matrix } from '@crossbind/example-lib-prebuilt-matrix/Matrix.h';
import { zlibVersion } from 'conan:zlib/zlib.h';
import { Counter } from './native/counter.rs';
import { Version } from 'cargo:semver';

await initNative();

While developing, start the app through `crossbind/node/dev`, and it builds when it needs to:

node --import crossbind/node/dev src/index.mjs
node --watch --watch-path=src/native --import crossbind/node/dev src/index.mjs   # build and restart on save
  • Before the app starts, it builds this machine's binary when the project's native sources, its crossbind config or `package.json`, or the native files and names its JavaScript imports changed since the last build it ran, or when the output is missing, the first start included. An edit to the rest of the code builds nothing, and a start with nothing changed costs a few tens of milliseconds.
  • It builds the addon when the project installs `@crossbind/core-embind-napi` and the wasm build otherwise, with the build's output on stderr. A build that fails stops the app with its error.
  • It builds before anything loads because a running process cannot swap the binary it loaded: a native import added while the app runs takes a restart, which `--watch` does. A dependency rebuilt in place, which leaves `package.json` as it was, takes a `crossbind build`.

`crossbind build -e node` itself finds these imports in the app's sources and binds them, constants and a dependency's functions only by the names imported, as a bundler does ([binding rule 9](../../api/cpp-binding-rules.md)). It writes the hooks that serve them, `dist/node/<format>.register.mjs` beside the entry, where `<format>` is `wasm` for the st-release wasm build and `napi` for an addon build. A deployed app starts with those, since `crossbind` is a dev dependency it may not have; they need nothing but `dist` and never build:

node --import ./dist/node/napi.register.mjs src/index.mjs

`NODE_OPTIONS="--import=./dist/node/napi.register.mjs"` does

Read more
Ships withcrossbind

Import C++ and Rust like JavaScript modules (WebAssembly & React Native)

Get the whole plugin

Other agents on crossbind.