Switching from yargs
A yargs alternative that is drop-in compatible: change one import, keep your code and tests, and gain --json, --schema, --mcp and shell completions — with no dependency outside the burgee family where yargs has six.
burgee is a yargs alternative you adopt by changing one import. burgee/yargs
implements yargs' API itself — the factory, the instance, the helpers — and yargs' own test
suite is the grade.
Migrate from yargs in one import
- import yargs from 'yargs';
- import { hideBin } from 'yargs/helpers';
+ import yargs from 'burgee/yargs';
+ import { hideBin } from 'burgee/yargs/helpers';Your program and your tests stay as they are. npx burgee migrate --dry-run rewrites
yargs, yargs/yargs and yargs/helpers across a codebase, prints the plan first, and
refuses — by file and line — anything it cannot rewrite mechanically.
Your types move with the import. burgee/yargs exports what a typed program reads from
@types/yargs — Argv, Arguments, CommandModule, Options, InferredOptionTypes and
the rest — so import yargs, { type Argv } from 'burgee/yargs' compiles, and a typed chain
infers argv exactly as it did.
Is it really compatible with yargs?
Compatibility is graded, not claimed. yargs' own test suite — vendored, unmodified apart
from the import specifier — runs against burgee/yargs in CI, beside a control that runs
the same suite against real yargs:
| passing | rate | |
|---|---|---|
burgee/yargs | 816 / 816 | 100.0% |
| yargs itself (control) | 814 / 816 | 99.8% |
From Compatibility, which npm run compat:page generates from the
oracle's last run; this table is copied from it and that page is the authority. Rates are
measured against the control's total, so a file that fails to import cannot flatter the
number.
What you gain over yargs
--json— every command's result in one stable envelope,{ "ok": true, "data": … }, and every failure as one{ "ok": false, "error": { "code", "message" } }on stdout, with the exit code the error names — a handler that throws included, which through 0.11.1 could escapeparseAsync()as a stack trace.--schema— the command tree as data, with a JSON Schema per command; no handler runs, so an agent can call it first.--mcp— the same commands as MCP tools over stdio. A command that declared nothing is listed aseffects: 'undeclared'with no hints;.effects('read_only')adds them and.effects('withheld')keeps a command out.- Completions —
completion bash | zsh | fish | pwsh, static scripts generated from the declaration. - An exit-code contract —
2means rewrite the command; any other non-zero means the command was fine and the world was not.
yargs offers middleware on one program; a burgee plugin is written once and shared across programs, and works on yargs syntax, commander syntax and native alike.
Weight against yargs
From the root README's Measured table (2026-10-08, one CI runner, generated by
npm run bench — see Benchmarks):
| burgee | yargs | |
|---|---|---|
| Runtime dependencies | 5, none outside the burgee family | 6 |
| Full CLI run over bare node | +20.3 ms | +75.0 ms |
| Installed size | 1690 KB | 515 KB |
The lighter-than-yargs gate — burgee/yargs lighter in a bundle than yargs — is met
(0.985×). Installed size is larger, and stays on the page.
When to switch
- You want your CLI usable by an AI agent without writing tool definitions by hand.
- You want fewer packages in your install tree: yargs brings six runtime dependencies, burgee none outside the burgee family.
- You want
--json,--schemaand completions from the definition you already wrote.
Switching from commander
A commander alternative that is drop-in compatible: change one import, keep your code and tests, and gain --json, --schema, --mcp and shell completions. Graded by commander's own test suite.
Switching from oclif
An oclif alternative, measured against it rather than dropped in: there is no burgee/oclif, so moving means rewriting each command class. When oclif is the better choice, when burgee is, and what the rewrite looks like.