mrkeyoor.com_
Sat 19 Sept 23:46 UTC
npmCLI & Toolingupdated 19 Sept 2026

yargs review

yargs 18.1.0 parses command-line arguments into an `argv` object while generating commands, option help, validation errors, and shell completions from one declaration graph. It supports positional values, aliases, types, choices, defaults, conflicts, implications, custom checks, coercion, middleware, environment variables, and config files. `parseAsync()` waits for promise-returning parsing stages and handlers. Version 18.1.0 ignores Bun when deriving the displayed binary name, adds Georgian localization, fixes German `count` text, and closes a local prototype-pollution path in config extension.

233.7Mdownloads / wk
Verdict

yargs 18.1.0 installed in 0.8 seconds with 14 packages and 2 MB, loaded through require and import, and returned 0 audit findings in our sandbox; it fits a Node CLI that needs a real command model. Enable strict parsing, await parseAsync for promises, and add @types/yargs when TypeScript declarations are needed.

We installed it

Lab card: what happened when we installed yargsScreenshot of yargs documentation
Install✓ · 0.8s14 packages on disk · 2 MB
ImportESM import works · require() works · ESM package with exports map
Browsern/acould not be bundled for the browser (Node-only code, most likely)
Typesno TypeScript types found
Known vulns00 critical · 0 high · 0 moderate · 0 low (npm audit)

Answers from our run

Does yargs install cleanly?

Yes. In a fresh container with an empty cache, npm install yargs finished in 0.8s, leaving 14 packages and 2 MB on disk. npm audit reported no known vulnerabilities.

Can yargs run in a browser?

Not directly: esbuild could not bundle it for the browser in our run, which normally means it depends on Node built-ins. Use it on the server, or find a browser-targeted alternative.

Does yargs work with both ESM and CommonJS?

Yes. Both import 'yargs' and require('yargs') worked in Node 22 in our run. The package is published as ESM with an exports map.

Does yargs include TypeScript types?

No type declarations were found in our install, so TypeScript users need their own declarations.

yargs or commander: which should you use?

commander: Choose it for a smaller command-oriented API with generated help and fewer parser switches. yargs 18.1.0 installed in 0.8 seconds with 14 packages and 2 MB, loaded through require and import, and returned 0 audit findings in our sandbox; it fits a Node CLI that needs a real command model.

When should you not use yargs?

A script has only a couple of fixed options; Node's util.parseArgs can keep that parser inside the standard library.

API stability4/5command(), option(), positional(), demandOption(), check(), middleware(), help(), parse(), and the argv model have long histories. Major versions still raise Node floors and alter packaging; version 18 requires particular Node 20 and 22 patch releases. Parser configuration also changes returned key names and collection behavior, so pin the major and snapshot both help output and representative argv results.
Docs4/5The project site and repository cover commands, option types, validation, config loading, environment mapping, middleware, completion, localization, parser controls, browser use, and API details. The breadth is searchable but dense, and TypeScript documentation depends on separately versioned @types/yargs. Examples could surface strict parsing and the need to await async handlers earlier.
Maintenance4/5GitHub showed a push on August 7, 2026, 208 open issues and pull requests, 11,514 stars, and an unarchived repository. Version 18.1.0 shipped on July 26 with Bun name handling, locale work, and a local prototype-pollution fix. Active releases track current Node lines, although the sizeable queue and major engine jumps create upgrade work for widely distributed CLIs.
Ecosystem5/5npm recorded 253,970,005 downloads for August 18 through 24, 2026. Many Node command-line programs and build tools depend on yargs or yargs-parser, and built-in completion, localization, middleware, environment mapping, and config loading avoid several extra packages. The separate DefinitelyTyped dependency remains a notable boundary for TypeScript users.

Discussed on

  1. hnShow HN: Build a Slack-Bot with Node.js and Yargs and Heroku6 points

Use it if

  • A Node CLI has several commands whose positional arguments, flags, and generated help should stay in one model.
  • Choices, required options, conflicts, implications, coercion, and domain checks must run before a command handler.
  • Configuration files and prefixed environment variables should merge into the same option names as command-line input.
  • Async middleware or handlers and generated Bash or Zsh completion are part of the product.
Skip it if

Setup reality

We installed yargs 18.1.0 in a fresh Node 22 Bookworm sandbox in 0.8 seconds. npm left 14 packages using 2 MB and reported 0 known vulnerabilities. The package declares 6 direct dependencies and 0 peers; it measures 412 KB unpacked and uses the MIT license. It is ESM with an exports map, but both require and ESM import worked in our checks. No bundled TypeScript declarations were found.

The engine range is unusually specific: Node ^20.19.0 || ^22.12.0 || >=23. Pass hideBin(process.argv) so the Node executable and script name do not become user arguments. Define the entire command tree before parsing because parse triggers validation and handlers. If any builder stage, coercion, check, middleware, or handler returns a promise, use and await parseAsync().

Strict behavior is not automatic. Pick strict(), strictOptions(), or strictCommands() based on whether pass-through arguments are allowed, then test misspellings. Scalar type conversion does not validate a port range, URL policy, or file existence. Parser settings also control camel-case expansion, duplicate arrays, number parsing, and handling after --; changing them can alter the argv shape without an obvious syntax error.

Our esbuild browser bundle failed even though yargs exposes ./browser; do not assume the package works in a browser build until the actual import path and bundler are tested. .env(prefix) and .config() can inject secrets into argv, so errors and debug output need redaction. Completion invokes command discovery, making network access and other side effects inside builder functions especially costly.

Patterns

Remove Node's argv prefix parse-arguments

#!/usr/bin/env node
import yargs from 'yargs';
import { hideBin } from 'yargs/helpers';

const argv = yargs(hideBin(process.argv)).parse();

hideBin accounts for runtime variations while removing the executable and script entries before parsing.

Type and constrain flags declare-options

const cli = yargs(hideBin(process.argv))
  .option('env', {
    alias: 'e',
    type: 'string',
    choices: ['dev', 'staging', 'prod'],
    demandOption: true,
  })
  .option('force', { type: 'boolean', default: false });

const argv = cli.parse();

choices validates the named environments. Type conversion alone does not enforce domain rules.

Add a positional command define-command

yargs(hideBin(process.argv))
  .command(
    'serve [port]',
    'start the server',
    (cli) => cli.positional('port', { type: 'number', default: 5000 }),
    (argv) => serve(argv.port),
  )
  .demandCommand(1, 'choose a command')
  .parse();

Help and completion can execute builders, so keep the builder free of network calls and other side effects.

Turn on strict parsing reject-unknown-input

yargs(hideBin(process.argv))
  .command('deploy', 'publish the release', {}, deploy)
  .strict()
  .parse();

strict() rejects unknown commands and options. Use a narrower strict mode only when one category intentionally passes through.

Wait for an async handler await-command

await yargs(hideBin(process.argv))
  .command('migrate', 'apply migrations', {}, async (argv) => {
    await runMigrations(argv);
  })
  .parseAsync();

parseAsync propagates promise completion and rejection; plain parse is insufficient when any parsing stage is asynchronous.

Map a prefixed environment read-environment

const argv = yargs(hideBin(process.argv))
  .env('MYAPP')
  .option('api-key', { type: 'string', demandOption: true })
  .parse();
// MYAPP_API_KEY maps to argv.apiKey

Do not print the full argv object in diagnostics once environment values may contain credentials.

Merge a selected JSON file load-config-file

const argv = yargs(hideBin(process.argv))
  .config('settings')
  .option('region', { type: 'string', default: 'us-east-1' })
  .parse();
// --settings ./deploy.json

Treat file values as untrusted input and document whether CLI, environment, or file settings win.

Express conflicts and implications validate-option-relations

const argv = yargs(hideBin(process.argv))
  .option('token', { type: 'string' })
  .option('anonymous', { type: 'boolean' })
  .option('upload', { type: 'string' })
  .conflicts('token', 'anonymous')
  .implies('upload', 'token')
  .strictOptions()
  .parse();

conflicts and implies run during parsing, before a handler sees an invalid option combination.

Alternatives

PackageRegistryPick it when
commandernpmChoose it for a smaller command-oriented API with generated help and fewer parser switches.
cacnpmChoose it for a compact command and option API often used by modern JavaScript build tools.
minimistnpmChoose it for bare argv conversion when the application will own commands, help, and validation.

More cli & tooling guides

commander · chalk · typescript · esbuild · click · vite · the whole shelf →

How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.