Building a tiny CLI with Commander

Real backend tools are command-line tools. git commit, docker run, kubectl apply. When you build a backend script, you want it to feel the same way: named flags, a help screen, and a clear exit code so other scripts can call it. That is what Commander gives you.

You absolutely can, and for a one-off script it is fine. But the moment you want named flags, default values, type coercion, required options, and a generated help screen, you are reinventing what Commander already does cleanly. Reach for the small library and spend your effort on the actual work.

before/cli.ts
typescript
import { program } from 'commander';

program
  .name('book-parser')
  .description('Read, validate, and clean a bookstore inventory file')
  .version('1.0.0')
  .requiredOption('-i, --input <path>', 'path to the raw input JSON file')
  .requiredOption('-o, --output <path>', 'path to save the cleaned JSON file')
  .parse(process.argv);

const options = program.opts();
console.log('Input:', options.input);
console.log('Output:', options.output);

Commander turns a script into a real command-line tool with named flags and help text.

Read it top to bottom. name, description, and version power the help screen. requiredOption declares a flag that must be passed. parse(process.argv) does the work of reading the command line. After parse, program.opts() gives you a typed object with your options. Half a dozen lines and you have a real CLI.

One more habit worth picking up early: always exit with a non-zero code when something fails. process.exit(1) on failure, process.exit(0) or just letting the program end on success. Other scripts and CI systems read the exit code to decide what to do next.

Quiz: Quiz

Loading practice…

Validation checklist: Wire the CLI to your validator

Loading practice…