Crust logoCrust

Quick Start

Scaffold, run, and extend a typed Crust CLI.

Create a new project

Create a project

npx create-crust@latest my-cli
cd my-cli
cli.ts
package.json
tsconfig.json
README.md
.gitignore

Run it

npm run dev -- Ada --greet Welcome
# Welcome, Ada!

The help() extension generates usage from the same definitions:

npm run dev -- --help
my-cli - A CLI built with Crust

Usage:
  my-cli [name] [options]

Arguments:
  [name]             Your name [default: "world"]

Options:
  -g, --greet                  Greeting to use [default: "Hello"]
  -v, --version                Show version number
  -h, --help                   Show help

Add a subcommand

Chain .command() onto the root:

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

import pkg from "../package.json" with { type: "json" };

const app = new Crust("my-cli", { description: "A CLI built with Crust", version: pkg.version })
	.extend(version(), help())
	.args({
		name: "name",
		type: "string",
		description: "Your name",
		default: "world",
	})
	.flags({
		name: "greet",
		type: "string",
		description: "Greeting to use",
		default: "Hello",
		short: "g",
	})
	.action(({ args, flags, stdout }) => {
		stdout(`${flags.greet}, ${args.name}!`);
	})
	.command("build", (command) =>
		command
			.flags({ name: "minify", type: "boolean", description: "Minify output" })
			.action(({ flags, stdout }) => stdout(`minify: ${flags.minify ?? false}`)),
	);

await app.execute();
npm run dev -- build --minify
# minify: true

npm run dev -- Ada
# Hello, Ada!

my-cli build routes to the subcommand; anything else still reaches the root action. Inline .command() suits app-local commands. Move to defineCommand and split files when a command needs its own file or reuse.

Build it

npm run build
npm run start Ada

crust build stages your selected artifact and npm packaging metadata in .crust/. npm is optional: standalone binaries embed their runtime and can also ship as release downloads or through Homebrew and other installers, without the Node-based npm launcher. Runtime packages still require their selected runtime. See Build and distribution for targets and output layouts.

create-crust and the crust CLI are themselves built with Crust; see the repository for working examples.

Manual setup

To add Crust without the scaffolder, follow the steps below from your project directory. If configuration files already exist, merge the settings rather than replacing them.

Choose your runtime

The runtime runs your CLI; the package manager installs dependencies. For Bun and Node.js, use whichever package-manager tab you prefer.

Use Bun 1.4 or later.

npm install @crustjs/core @crustjs/extensions
npm install -D typescript @types/bun

Set the module format in package.json, keeping the dependencies added above:

package.json (partial)
{
  "type": "module"
}
tsconfig.json
{
  "compilerOptions": {
    "target": "ESNext",
    "lib": ["ESNext"],
    "types": ["bun"],
    "module": "Preserve",
    "moduleResolution": "bundler",
    "allowImportingTsExtensions": true,
    "verbatimModuleSyntax": true,
    "noEmit": true,
    "strict": true,
    "skipLibCheck": true
  },
  "include": ["src"]
}

Create the entrypoint

Create src/cli.ts. The same code works on all three runtimes:

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();

Run and check it

bun run src/cli.ts Ada
bun run src/cli.ts --help
bunx tsc --noEmit

Build when ready

You don't need @crustjs/crust to run the source. When you're ready to distribute your CLI, follow Build and distribution to add the build tooling and package configuration.

Next steps

The Guide walks through each layer of a Crust application, from arguments and flags to Extensions, Contexts, testing, and distribution. Pick the topic you need next.

On this page