getopts
getopts is a small, dependency-free parser that turns an argv array into an object of flags plus a special underscore array for positional operands. It understands grouped short flags, long options, aliases, defaults, negated booleans, repeated values, an end-of-options marker, and early stopping for hand-built subcommands. It ships both ESM and CommonJS entry points and TypeScript declarations, but it deliberately stops at parsing: help text, command dispatch, validation, prompts, and error messages remain your application's job.
getopts is a good low-level choice when all you need is fast argv parsing and you are willing to own validation and help. Do not install it expecting a CLI framework, precise inferred types, or conservative string handling.
Use it if
- You need to parse flags in a small Node CLI without adopting a command framework or adding runtime dependencies
- You are replacing minimist and want a similarly direct object result with aliases, booleans, strings, defaults, and positional operands
- You need both import and require consumers from the same package and are comfortable validating the parsed result yourself
- You want stopEarly parsing so a small dispatcher can hand the remaining argv tokens to a subcommand
- You need generated help, usage errors, shell completion, command classes, or nested routing: getopts only parses tokens and provides none of those application-level features
- You want schema-derived TypeScript types: ParsedOptions uses an any-valued index signature, so aliases and option declarations do not produce a precise return type
- Implicit coercion is unacceptable: untyped values such as 001, 3.14, and false become numbers or a boolean, while other text remains a string
- You expect a recent release cadence: version 2.3.0 was published in February 2021, although the repository received a later push in July 2025
- You need parser-generated validation for required options, allowed choices, ranges, or mutually exclusive flags; all of those checks must be written after parsing
Setup reality
npm install getopts is the whole dependency setup. There are no peer dependencies, native modules, credentials, generated files, or configuration files. The package exposes an ES module default from index.js and a CommonJS export from index.cjs, so both import getopts from 'getopts' and require('getopts') are supported. The surprises are behavioral. Pass process.argv.slice(2), not the complete process.argv array. Unless an option is listed in boolean, a following non-option token becomes its value; this means --verbose file.txt consumes file.txt instead of leaving it positional. Unless an option is listed in string, values that JavaScript's numeric conversion accepts become numbers, and the exact text false becomes boolean false. Declared string and boolean options are always present even when omitted, as an empty string or false. Repeating a key changes its result from a scalar to an array, so downstream code must allow both shapes. A separate negative number begins with a dash and may be read as another option; use an equals form such as --count=-1 when that value is intended. The unknown callback filters only names not mentioned by alias, boolean, string, or default settings, and returning false silently discards them rather than throwing. Type declarations are included, but the dynamic result keys are typed as any. There is no automatic help or invalid-flag error, so production CLIs need their own usage text, validation, and exit-code policy.
Patterns
Parse flags and positional operandsparse-process-arguments
import getopts from 'getopts';
const options = getopts(process.argv.slice(2));
console.log(options.verbose);
console.log(options._);Always slice off the Node executable and script path. Non-option tokens are collected in options._.
Keep short and long aliases in syncdefine-aliases
const options = getopts(['-o', 'dist/app.js'], {
alias: {output: ['o', 'f']},
});
console.log(options.output); // dist/app.js
console.log(options.o); // dist/app.jsEvery alias is written into the result. Repeated values share the same array object across the canonical name and its aliases.
Prevent a boolean from consuming the next operandforce-boolean-flag
const options = getopts(['--verbose', 'report.txt'], {
boolean: ['verbose'],
});
console.log(options.verbose); // true
console.log(options._); // ['report.txt']Without the boolean declaration, report.txt becomes the value of verbose rather than a positional operand.
Keep numeric-looking input as textpreserve-string-value
const options = getopts(['--zip=00123'], {
string: ['zip'],
});
console.log(options.zip); // '00123'Undeclared values are coerced when numeric conversion succeeds, which would turn 00123 into 123.
Apply defaults and aliasesset-default-values
const options = getopts([], {
alias: {port: 'p'},
default: {port: 3000, color: true},
});
console.log(options.port, options.p); // 3000 3000Defaults are copied to known aliases. A value provided on argv replaces the default for the canonical key and aliases.
Read a repeated option as an arraycollect-repeated-options
const options = getopts([
'--tag=docs',
'--tag=release',
]);
console.log(options.tag); // ['docs', 'release']The first occurrence is a scalar; only the second occurrence turns it into an array. Normalize with [].concat(options.tag ?? []) if both cases are valid.
Support a no-prefixed booleannegate-boolean-option
const options = getopts(['--no-color'], {
boolean: ['color'],
default: {color: true},
});
console.log(options.color); // falseAny long option beginning --no- is interpreted as the positive key set to false, even without a boolean declaration.
Stop option parsing with a double dashpass-through-operands
const options = getopts([
'--quiet',
'--',
'--child-flag',
'file.txt',
]);
console.log(options._); // ['--child-flag', 'file.txt']Everything after the standalone -- is positional, which is the safest way to pass flags to a child process.
Allow only declared option namesfilter-unknown-options
const allowed = new Set(['verbose', 'v', 'output', 'o']);
const options = getopts(process.argv.slice(2), {
alias: {verbose: 'v', output: 'o'},
unknown: name => allowed.has(name),
});Returning false drops an unknown option silently. Throw inside the callback or compare argv separately if invalid flags must produce an error.
Stop at the first operand for subcommand dispatchdispatch-subcommand
const root = getopts(process.argv.slice(2), {
boolean: ['verbose'],
stopEarly: true,
});
const [command, ...subargv] = root._;
if (command === 'build') {
const build = getopts(subargv, {string: ['out']});
// runBuild(build)
}With stopEarly, every token from the first operand onward goes into _. Parse subargv separately with the selected command's option rules.
Bind a negative number with equals syntaxparse-negative-number
const options = getopts(['--offset=-5']);
console.log(options.offset); // -5A separate -5 token starts with a dash and can be parsed as an option. The equals form makes the negative number unambiguous.
Use the CommonJS exportload-commonjs
const getopts = require('getopts');
const options = getopts(process.argv.slice(2), {
boolean: ['help'],
});The package export map selects index.cjs for require and index.js for import, so no interop .default access is needed.
Alternatives
| Package | Registry | Pick it when |
|---|---|---|
| minimist | npm | Choose it when compatibility with minimist's long-established parsing behavior matters more than getopts' smaller focused implementation |
| mri | npm | Choose it for another compact dependency-free parser with a similar flags-and-operands result |
| commander | npm | Choose it when the CLI also needs subcommands, generated help, validation, action handlers, and a larger support ecosystem |