CLI Forge vs. yargs

Yargs is one of the most established CLI libraries in the Node.js ecosystem. It shares a similar fluent API style with CLI Forge.

CLI Forge strengths

Shared strengths

  • Config files with extends — Both support config files with extends-based inheritance. CLI Forge additionally provides automatic file discovery, write-back, and per-key provenance tracking (example).
  • Shell completions — Both generate shell completion scripts. Yargs uses .completion() for bash/zsh. CLI Forge supports bash, zsh, fish, and PowerShell (example).
  • Localization — Yargs has built-in i18n with .locale() and .updateStrings(). CLI Forge supports localization through middleware (example) and integrates with libraries like i18next.
  • Middleware — Both support middleware. CLI Forge's version additionally supports typed argument accumulation across the middleware chain (example).
  • Env variable support — Yargs has .env(). CLI Forge has declarative env var mapping (example).
  • Browser support — Both support browsers. Yargs has browser docs. CLI Forge has browser usage.

yargs strengths

  • Ecosystem maturity — Extensive community documentation, Stack Overflow answers, and third-party integrations.
  • Filesystem routing — .commandDir() loads commands from a directory structure.
  • Usage string parsing — Define options from usage strings like '--port <number>'.
  • Deno support — Officially supports Deno in addition to Node.js and browsers.

Side-by-side example

The same CLI — a greet command with hello and goodbye subcommands — implemented in both libraries.

import yargs from 'yargs';
import { hideBin } from 'yargs/helpers';

yargs(hideBin(process.argv))
  .command(
    'hello',
    'Say hello to someone',
    (yargs) =>
      yargs
        .option('name', {
          type: 'string',
          description: 'Name to greet',
          default: 'World',
        })
        .option('uppercase', {
          type: 'boolean',
          description: 'Print greeting in uppercase',
          default: false,
        }),
    (args) => {
      const msg = `Hello, ${args.name}!`;
      console.log(args.uppercase ? msg.toUpperCase() : msg);
    }
  )
  .command(
    'goodbye',
    'Say goodbye to someone',
    (yargs) =>
      yargs
        .option('name', {
          type: 'string',
          description: 'Name to bid farewell',
          default: 'World',
        })
        .option('formal', {
          type: 'boolean',
          description: 'Use formal farewell',
          default: false,
        }),
    (args) => {
      console.log(
        args.formal ? `Farewell, ${args.name}.` : `Bye, ${args.name}!`
      );
    }
  )
  .demandCommand(1)
  .help()
  .parse();
import { cli } from 'cli-forge';

cli('greet')
  .command('hello', {
    description: 'Say hello to someone',
    builder: (args) =>
      args
        .option('name', {
          type: 'string',
          description: 'Name to greet',
          default: 'World',
        })
        .option('uppercase', {
          type: 'boolean',
          description: 'Print greeting in uppercase',
          default: false,
        }),
    handler: (args) => {
      const msg = `Hello, ${args.name}!`;
      console.log(args.uppercase ? msg.toUpperCase() : msg);
    },
  })
  .command('goodbye', {
    description: 'Say goodbye to someone',
    builder: (args) =>
      args
        .option('name', {
          type: 'string',
          description: 'Name to bid farewell',
          default: 'World',
        })
        .option('formal', {
          type: 'boolean',
          description: 'Use formal farewell',
          default: false,
        }),
    handler: (args) => {
      console.log(
        args.formal ? `Farewell, ${args.name}.` : `Bye, ${args.name}!`
      );
    },
  })
  .forge();

Back to comparison overview · View all framework examples