Crust logoCrust

Manual Installation

Install Crust manually with the core framework, plugins, and CLI tooling.

If you're starting a new project, the easiest way is bun create crust my-cli. See the Quick Start guide.

Install

Choose the dependency layout that matches your distribution strategy:

# Core framework and plugins are build-time inputs
bun add -d @crustjs/core @crustjs/plugins

# CLI tooling (crust build)
bun add -d @crustjs/crust @types/bun typescript
# Core framework and plugins are runtime dependencies
bun add @crustjs/core @crustjs/plugins

# CLI tooling + types are dev dependencies
bun add -d @crustjs/crust @types/bun typescript
src/cli.ts
import { Crust } from "@crustjs/core";
import { helpPlugin, versionPlugin } from "@crustjs/plugins";

Standalone binaries are recommended for most CLIs because users can run them without Bun or project dependencies installed.

If you distribute standalone binaries (crust build + dist/), keeping all Crust packages in devDependencies is valid. If you distribute as a runtime package, keep @crustjs/core and @crustjs/plugins in dependencies.

CLI Patterns

You can structure your CLI as either a single file (minimal) or a modular file-split app using .sub().

Use this when your CLI is small and you want everything in one place.

src/cli.ts
#!/usr/bin/env bun

import { Crust } from "@crustjs/core";

const main = new Crust("my-cli")
  .meta({ description: "My CLI tool" })
  .run(() => {
    console.log("Hello from my CLI!");
  });

await main.execute();
bun run src/cli.ts

Use this when your CLI grows and you want commands in separate files.

src/app.ts
import { Crust } from "@crustjs/core";

export const app = new Crust("my-cli")
  .meta({ description: "My CLI tool" })
  .flags({
    greet: {
      type: "string",
      description: "Greeting to use",
      default: "Hello",
      short: "g",
      inherit: true,
    },
  });
src/commands/greet.ts
import { app } from "../app.ts";

export const greetCmd = app
  .sub("greet")
  .meta({ description: "Greet someone" })
  .args([
    {
      name: "name",
      type: "string",
      description: "Your name",
      default: "world",
    },
  ])
  .run(({ args, flags }) => {
    console.log(`${flags.greet}, ${args.name}!`);
  });
src/cli.ts
#!/usr/bin/env bun

import { helpPlugin, versionPlugin } from "@crustjs/plugins";
import pkg from "../package.json";
import { app } from "./app.ts";
import { greetCmd } from "./commands/greet.ts";

await app
  .use(versionPlugin(pkg.version))
  .use(helpPlugin())
  .command(greetCmd)
  .execute();
bun run src/cli.ts greet world

Adding to package.json

For a distributable CLI, configure your package.json based on the selected mode:

Raw binaries (default):

package.json
{
  "name": "my-cli",
  "version": "1.0.0",
  "type": "module",
  "files": ["dist"],
  "bin": {
    "my-cli": "dist/cli"
  },
  "scripts": {
    "dev": "bun run src/cli.ts",
    "build": "crust build",
    "prepack": "bun run build",
    "start": "./dist/cli"
  },
  "devDependencies": {
    "@crustjs/core": "latest",
    "@crustjs/plugins": "latest",
    "@crustjs/crust": "latest",
    "@types/bun": "latest",
    "typescript": "^5"
  }
}

Per-OS npm packages (optional):

To publish via npm with automatic platform detection, add the package and publish scripts:

package.json
{
  "name": "my-cli",
  "version": "1.0.0",
  "type": "module",
  "files": ["dist"],
  "bin": {
    "my-cli": "dist/cli"
  },
  "scripts": {
    "dev": "bun run src/cli.ts",
    "build": "crust build",
    "package": "crust build --package",
    "publish": "crust publish --stage-dir dist/npm",
    "prepack": "bun run build",
    "start": "./dist/cli"
  },
  "devDependencies": {
    "@crustjs/core": "latest",
    "@crustjs/plugins": "latest",
    "@crustjs/crust": "latest",
    "@types/bun": "latest",
    "typescript": "^5"
  }
}

The package script creates platform-specific packages in dist/npm/. The publish script publishes them in manifest order. See Per-OS Distribution for details.

If you need public build-time constants, crust build can read PUBLIC_* values from Bun's cwd env by default, or you can pass --env-file for explicit env files. See Environment Variables for the full runtime-vs-build-time model.

package.json
{
  "name": "my-cli",
  "version": "1.0.0",
  "type": "module",
  "files": ["dist"],
  "bin": {
    "my-cli": "dist/cli.js"
  },
  "scripts": {
    "dev": "bun run src/cli.ts",
    "build": "bun build src/cli.ts --target bun --outfile dist/cli.js",
    "prepack": "bun run build",
    "start": "bun run dist/cli.js"
  },
  "dependencies": {
    "@crustjs/core": "latest",
    "@crustjs/plugins": "latest"
  },
  "devDependencies": {
    "@crustjs/crust": "latest",
    "@types/bun": "latest",
    "typescript": "^5"
  }
}

Requirements

  • Bun — Crust is built for the Bun runtime. Install from bun.sh.
  • TypeScript — Recommended for full type inference. Crust works with plain JavaScript, but you'll miss out on typed args and flags.

On this page