Crust logoCrust

Runtime support

Run the same CLI on Bun, Node.js, and Deno, and know where they differ.

Crust's command API works on Bun, Node.js, and Deno. Start with the same entrypoint; change the command that runs it.

Run the same CLI

After installing Crust, save this as src/cli.ts:

src/cli.ts
import { Crust } from "@crustjs/core";
import { help } from "@crustjs/extensions";

const app = new Crust("my-cli")
	.extend(help())
	.args({ name: "name", type: "string", default: "world" })
	.action(({ args, stdout }) => {
		stdout(`Hello, ${args.name}!`);
	});

await app.execute();
RuntimeLibrary minimumRun the TypeScript example
Bun1.4+bun run src/cli.ts Ada
Node.js24+node src/cli.ts Ada
Deno2.8+deno run --allow-env src/cli.ts Ada

All three print:

Hello, Ada!

Node.js 24+ can run both the published libraries and the TypeScript command above. Use "type": "module" in package.json and erasable TypeScript syntax—no enums or parameter properties. See Node's type stripping for its limits.

Choose a runtime for your project

npx create-crust@latest my-cli --runtime node

This selects Node.js for the generated dev script, TypeScript settings, and target runtime. The next wizard question selects the build output independently; pass --artifact package or --artifact binary to skip it. All six combinations are supported, with experimental Deno package bundling. Defaults are Node.js packages and Bun/Deno binaries. Use --runtime bun or --runtime deno instead; Bun is the default runtime. See package setup for the build and release scripts.

The package manager does not choose the runtime. npm, pnpm, Yarn, and Bun can install dependencies for either Bun or Node.js projects. The Deno scaffold uses deno install; for manual setup, use deno add npm:@crustjs/core npm:@crustjs/extensions.

Deno permissions

The example above grants --allow-env because Crust reads environment variables during execution and terminal styling. Add permissions for the work your CLI does:

Your CLI needs to…Add this flag before src/cli.ts
Read files in the current project--allow-read=.
Write generated files to dist--allow-write=./dist
Call an API--allow-net=api.example.com
Run Git--allow-run=git

These grants apply to library code too. Subprocesses run outside Deno's sandbox, so only allow trusted executables. See Deno permissions for scoping and other permission types.

Scaffolded Deno projects grant all permissions

The generated dev and start scripts use -A (all permissions). For sandboxed source execution, replace -A in dev with only the grants you need. Deno executables produced by crust build are also compiled with -A; choosing Deno does not make those binaries sandboxed. Deno runtime packages carry no grants: their users choose them with deno run or deno install.

Build separately from running

You don't need Bun to run Node.js or Deno source. crust build is separate, Bun-powered tooling, even when producing Node.js or Deno output. The packaged CLI can use its embedded Bun runtime; Deno binaries and Deno runtime packages additionally require deno on PATH, and Node.js binaries a node on PATH that meets tsdown's executable requirements (Node.js 26+ with the bundled tsdown).

The runtime does not choose the output: crust.artifact does. A runtime package is JavaScript for the user's installed Bun, Node.js, or Deno (experimental); a standalone binary embeds Bun, Deno, or Node.js and needs no separately installed JavaScript runtime.

The distribution channel is a separate choice. npm's generated launcher needs Node.js to select and start a binary; direct downloads, Homebrew, or other installers can run that same binary without the launcher or Node.js. crust publish handles npm only. Continue to Build and distribution for targets and release layouts.

On this page