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
- Type accumulation — Each
.option()call progressively builds a TypeScript type. Yargs relies on external@types/yargsdefinitions that may lag behind releases. - Object options —
type: 'object'with fully typedpropertiesand per-property declarations (example). Yargs supports dot-notation (e.g.,--foo.bar=baz) but without TypeScript inference of the nested structure. - Documentation generation —
cli-forge generate-docsproduces markdown or JSON from your CLI definition. - Interactive shell — Opt-in REPL for exploring commands interactively (example).
- Test harness —
TestHarnesstests parsing and command resolution without running handlers (example). - Zod integration — Middleware for Zod schema validation (example). Yargs validation is limited to
.check()callbacks.
Shared strengths
- Config files with
extends— Both support config files withextends-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();