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:
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();
| Runtime | Library minimum | Run the TypeScript example |
|---|---|---|
| Bun | 1.4+ | bun run src/cli.ts Ada |
| Node.js | 24+ | node src/cli.ts Ada |
| Deno | 2.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 nodeThis 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.