Skip to content

Introduction

clibuilder is a library for building command line applications in Node.js. You describe your CLI as a tree of commands; clibuilder parses process.argv, resolves which command was invoked, validates the arguments and options against the schemas you declared, loads the config file if the command asks for one, and calls your run().

The core idea is that a command’s declaration is its type. When you write:

command({
name: 'sum',
arguments: [{ name: 'values', description: 'values to add', type: t.array(t.number()) }],
options: { verbose: { description: 'be chatty' } },
run(args) {
// args.values: number[]
// args.verbose: boolean | undefined
}
})

there is no second place to declare the shape of args — it is inferred from arguments and options, using the t type descriptors.

clibuilder is built on args-minus, a dependency-free argument parser that you can also use on its own in Node.js, Deno and Bun.

  • Commands and sub-commands — my-cli repo create nests to any depth, with aliases. See Commands.
  • Typed arguments and options — declared with t, inferred into run(args), validated before run() is reached. See Arguments & Options.
  • Config files — JSON, YAML, cjs, or mjs, resolved by convention from the CLI name, and validated per command against any Standard Schema. See Configuration.
  • Plugins — commands published as separate packages, loaded by @clibuilder/plugins when a CLI opts in. See Plugins.
  • A generated help message — --help at every level, built from the descriptions you already wrote.
  • A UI object — this.ui.info/warn/error/debug, with display level driven by --verbose, --silent, and --debug-cli. See UI.
  • A test helper — testCommand() runs a command in-process and returns its result plus the messages it printed.
  • An opt-in startup cache — enableCompileCache() turns on Node’s V8 compile cache from your bin script.
  • Agent-facing output is the default. With output: 'axi', the value run() returns is printed on stdout in the format the caller asks for with --format (toon, json or text). A CliError or a usage error is reported once, with a code, and every ui.* message is a diagnostic on stderr. output: 'console' keeps the 11 behaviour, and is not deprecated.
  • t replaces zod. Arguments and options declare their type with t, and config takes any Standard Schema from your own dependency.
  • A slimmer core. Config loads through .use(config()), plugins through @clibuilder/plugins, and the AXI helpers come from clibuilder/axi.

See Upgrading to 12 for every change, with the fix for each and a codemod for the mechanical parts.