Skip to main content

Commander vs yargs in 2026: CLI Argument Parsing

·PkgPulse Team

TL;DR

Commander for simple CLIs; yargs for complex CLIs with subcommands, completions, and built-in validation. Commander (~50M weekly downloads) is minimal, zero-dependency, and used in Vue CLI, Create React App, and many popular tools. yargs (~30M downloads) is heavier but auto-generates help, handles validation, and has better subcommand support. For most CLIs, Commander's simplicity wins.

Key Takeaways

  • Commander: ~50M weekly downloads — yargs: ~30M (npm, March 2026)
  • Commander is zero-dependency — yargs has 3 dependencies
  • yargs generates help automatically — more detailed --help output
  • Both support subcommands — yargs has better subcommand file loading
  • Commander is TypeScript-first — v8+ has excellent type definitions

Basic CLI

// Commander — simple, clean API
const { Command } = require('commander');
const program = new Command();

program
  .name('my-tool')
  .description('A useful CLI tool')
  .version('1.0.0');

program
  .command('deploy')
  .description('Deploy to production')
  .argument('<environment>', 'Target environment (staging|production)')
  .option('-f, --force', 'Force deploy without confirmation')
  .option('-t, --timeout <seconds>', 'Deployment timeout', '60')
  .action((environment, options) => {
    console.log(`Deploying to ${environment}...`);
    if (options.force) console.log('Forcing deployment');
    console.log(`Timeout: ${options.timeout}s`);
  });

program.parse();
// yargs — similar but more config
const yargs = require('yargs/yargs');
const { hideBin } = require('yargs/helpers');

yargs(hideBin(process.argv))
  .scriptName('my-tool')
  .command(
    'deploy <environment>',
    'Deploy to production',
    (yargs) => {
      yargs
        .positional('environment', {
          describe: 'Target environment',
          choices: ['staging', 'production'], // Auto-validated
        })
        .option('force', {
          alias: 'f',
          type: 'boolean',
          description: 'Force deploy without confirmation',
        })
        .option('timeout', {
          alias: 't',
          type: 'number',
          default: 60,
          description: 'Deployment timeout in seconds',
        });
    },
    (argv) => {
      console.log(`Deploying to ${argv.environment}...`);
    }
  )
  .demandCommand(1, 'Please specify a command')
  .help()
  .argv;

TypeScript Support

// Commander v8+ — full TypeScript types
import { Command } from 'commander';

interface DeployOptions {
  force: boolean;
  timeout: string;
}

const program = new Command();

program
  .command('deploy')
  .argument('<environment>', 'Target environment')
  .option('-f, --force', 'Force deploy', false)
  .option('-t, --timeout <secs>', 'Timeout', '60')
  .action((environment: string, options: DeployOptions) => {
    // Both typed correctly
  });
// yargs — TypeScript with inference
import yargs from 'yargs/yargs';

interface DeployArgs {
  environment: 'staging' | 'production';
  force: boolean;
  timeout: number;
}

yargs(hideBin(process.argv))
  .command<DeployArgs>(
    'deploy <environment>',
    'Deploy to production',
    (yargs) => yargs
      .positional('environment', { type: 'string', choices: ['staging', 'production'] as const })
      .option('force', { type: 'boolean', default: false })
      .option('timeout', { type: 'number', default: 60 }),
    (argv) => {
      // argv is DeployArgs — typed
      argv.environment; // 'staging' | 'production'
      argv.timeout;     // number
    }
  )
  .argv;

Auto-generated Help

# Commander help output:
$ my-tool deploy --help
Usage: my-tool deploy [options] <environment>

Deploy to production

Arguments:
  environment  Target environment (staging|production)

Options:
  -f, --force              Force deploy without confirmation
  -t, --timeout <seconds>  Deployment timeout (default: "60")
  -h, --help               display help for command

# yargs help output (more detailed):
$ my-tool deploy --help
my-tool deploy <environment>

Deploy to production

Positionals:
  environment  Target environment  [string] [required] [choices: "staging", "production"]

Options:
  --force, -f    Force deploy without confirmation  [boolean] [default: false]
  --timeout, -t  Deployment timeout in seconds      [number] [default: 60]
  --help, -h     Show help                          [boolean]
  --version, -v  Show version number                [boolean]

yargs generates more structured help with types and defaults shown.


When to Choose

Choose Commander when:

  • Simple CLI with straightforward commands
  • Zero-dependency is important (bundled CLIs, npm packages)
  • You prefer minimal API surface
  • TypeScript project (Commander v8+ has excellent types)
  • Most popular CLIs in the JS ecosystem use Commander

Choose yargs when:

  • Complex CLI with many subcommands and options
  • Built-in validation (choices, required args)
  • Shell completion generation
  • More detailed auto-generated help matters
  • You need middleware/before hooks on commands

Compare Commander and yargs package health on PkgPulse.

Comments

Stay Updated

Get the latest package insights, npm trends, and tooling tips delivered to your inbox.