CLI Forge vs. util.parseArgs

util.parseArgs is Node.js's built-in argument parser, available since Node.js v18.3.0 (stable in v20.0.0). It is intentionally minimal — a low-level primitive for simple scripts.

CLI Forge strengths

CLI Forge provides everything that util.parseArgs deliberately excludes:

Shared strengths

util.parseArgs strengths

  • Zero dependencies, built-in — Part of Node.js core. No installation needed.
  • Minimal API surface — A single function call with a simple config object. No abstractions to learn.
  • Tokens API — Returns detailed parse tokens for custom post-processing, useful when building your own parser on top.
  • No lock-in — No supply chain risk. Maintained as long as Node.js exists.

util.parseArgs is best suited for simple scripts with a handful of flags. For anything involving subcommands, validation, help text, or type safety, a library like CLI Forge will save significant effort.

Side-by-side example

The same CLI — a greet command with hello and goodbye subcommands — implemented in both approaches. Note how util.parseArgs requires entirely manual subcommand dispatch and help generation.

import { parseArgs } from 'node:util';

// Node.js util.parseArgs is deliberately minimal — it has no
// concept of subcommands, help generation, or type coercion
// beyond string/boolean. Everything else is manual.

const { values, positionals } = parseArgs({
  args: process.argv.slice(2),
  options: {
    name: { type: 'string', default: 'World' },
    uppercase: { type: 'boolean', default: false },
    formal: { type: 'boolean', default: false },
  },
  allowPositionals: true,
  strict: true,
});

const [command] = positionals;

if (command === 'hello') {
  const msg = `Hello, ${values.name}!`;
  console.log(values.uppercase ? msg.toUpperCase() : msg);
} else if (command === 'goodbye') {
  console.log(
    values.formal
      ? `Farewell, ${values.name}.`
      : `Bye, ${values.name}!`
  );
} else {
  console.log('Usage: greet <hello|goodbye> [options]');
  console.log('  --name <string>   Name to greet (default: World)');
  console.log('  --uppercase       Print greeting in uppercase');
  console.log('  --formal          Use formal farewell');
}
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