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-cliRun it
npm run dev -- Ada --greet Welcome
# Welcome, Ada!The help() extension generates usage from the same definitions:
npm run dev -- --helpmy-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 helpAdd a subcommand
Chain .command() onto the root:
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 Adacrust 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/bunSet the module format in package.json, keeping the dependencies added above:
{
"type": "module"
}{
"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:
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 --noEmitBuild 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.