Back to Node.js tutorials
Advanced16 min read

CLI Tools & Automation

Build command-line tools with yargs or commander, spawn child processes, and publish npm packages.

CLI Frameworks

commander and yargs parse argv, define subcommands, options, and help text. They validate input and generate --help automatically.

Structure CLIs with bin entry in package.json pointing to a shebang script: #!/usr/bin/env node. Use chalk or picocolors for readable output.

Return non-zero exit codes on failure so shell scripts and CI can detect errors.

  • Support --version and --help on all tools
  • Read config from env vars with CLI flags overriding
  • Write integration tests spawning the CLI with execa
#!/usr/bin/env node
import { program } from 'commander';

program
  .name('deploy-cli')
  .command('push <env>')
  .action(async (env) => { await deploy(env); });

program.parse();

Child Processes

child_process.spawn runs external commands with streaming stdout/stderr. exec runs shell commands with buffered output—avoid exec with untrusted input.

Pipe child output to parent stdio for transparent UX in dev scripts. Handle exit codes and signals for cleanup.

Use worker_threads instead of spawn when sharing memory or CPU work inside Node without shelling out.

  • Never pass user input directly to shell exec
  • Set cwd and env explicitly for reproducible scripts
  • Kill child trees on SIGINT during local dev
import { spawn } from 'node:child_process';

const child = spawn('npm', ['test'], { stdio: 'inherit' });
child.on('exit', code => process.exit(code ?? 0));

Publishing Packages

Scope packages @org/name for organizations. Prepublish scripts run tests and build dist. Use files field in package.json to whitelist published artifacts.

Semantic versioning communicates breaking changes. Document CLI usage in README with examples.

Consider npx-friendly global-less distribution so users run npx @org/tool without global install.

  • Add repository and bugs fields for npm page links
  • Sign commits and enable npm 2FA for publish access
  • Changelog entries for every public release

Get In Touch


Ready to discuss your next project? Drop me a message.