Crust logoCrust

Arguments

Define positional arguments with types, defaults, and validation.

Arguments are positional values passed to your CLI without a flag name. They're defined as an ordered array via .args(), and Crust maps them to named, typed values.

my-cli serve 3000 localhost
#            ^^^^  ^^^^^^^^^
#            arg 1  arg 2

Defining Arguments

Arguments are defined with the .args() method. Order matters — the first argument definition maps to the first positional value:

const cmd = new Crust("serve")
  .args([
    { name: "port", type: "number", default: 3000 },
    { name: "host", type: "string", default: "localhost" },
  ])
  .run(({ args }) => {
    console.log(`Listening on ${args.host}:${args.port}`);
  });

Argument Properties

Each argument is an ArgDef object with properties like name, type, description, default, required, and variadic. See the ArgDef reference for the full property table.

Types

Positional arguments accept the same six built-in type literals as flags: string, number, boolean, url, path, and json. See Types for the full semantics, error modes, and the parse escape hatch for custom transformations.

Required Arguments

Mark an argument as required to error when it's missing:

.args([
  { name: "name", type: "string", required: true },
])
$ my-cli
# Error: Missing required argument "<name>"

When required is true, the inferred type is guaranteed (no | undefined).

Default Values

Provide a default for optional arguments:

.args([
  { name: "port", type: "number", default: 3000 },
])

When a default is set, the argument is always present in args — the inferred type is guaranteed (no | undefined).

Optional Arguments

Arguments without required or default are optional. Their type includes | undefined:

new Crust("example").args([{ name: "name", type: "string" }]).run(({ args }) => {
  args.name; // string | undefined
});

Variadic Arguments

The last argument can be variadic, collecting all remaining positional values into an array:

const cmd = new Crust("copy")
  .args([
    { name: "destination", type: "string", required: true },
    { name: "files", type: "string", variadic: true },
  ])
  .run(({ args }) => {
    args.destination; // string
    args.files; // string[]
    for (const file of args.files) {
      console.log(`Copying ${file} to ${args.destination}`);
    }
  });
my-cli /output file1.txt file2.txt file3.txt

Only the last argument can be variadic. Crust enforces this at both compile time and runtime. Placing variadic: true on a non-last argument produces a type error.

Variadic arguments with required: true error when no values are provided. Without required, an empty array is returned.

The inferred TypeScript type is always T[] — never T[] | undefined — regardless of required. The required flag only controls whether an empty array fails validation; it does not change the runtime shape or the inferred type.

Choices

Use choices on a string positional argument to declare a static enum of valid values:

const cmd = new Crust("deploy")
  .args([{ name: "target", type: "string", choices: ["browser", "bun", "node"] }] as const)
  .run(({ args }) => {
    args.target; // string
  });

choices is validated at parse time — passing a value outside the list throws CrustError("PARSE", …) before any parse transform runs. Shell-completion plugins also consume choices to emit value candidates. choices is only available on string-typed args; using it on number or boolean args is a compile-time error. See the API reference for details.

The -- Separator

Arguments after -- are collected into rawArgs and not processed as positional arguments or flags:

.run(({ args, rawArgs }) => {
  // rawArgs contains everything after --
  console.log("Raw args:", rawArgs);
})
my-cli build -- --some-flag --passed-through
# rawArgs: ["--some-flag", "--passed-through"]

This is useful for forwarding arguments to child processes.

Type Inference

Crust infers argument types from your definitions — required and default guarantee the value, otherwise it's T | undefined. Variadic arguments always return an array. See the full inference rules for all cases.

On this page