minimist
minimist is the minimal argv parser: one function that turns process.argv into an object of flags and positionals, with aliases, defaults, booleans, and '--' handling. It is 'the guts of optimist's argument parser without all the fanciful decoration', at 1.3KB gzipped with zero dependencies. Its 149M weekly downloads are almost entirely transitive, since half of older npm depends on it somewhere. After prototype-pollution incidents, stewardship moved to the minimistjs org; the current 1.2.8 dates from February 2023.
For years the correct tiny argv parser, and it still works fine; but on any Node from the last few years, util.parseArgs does the same job built-in and stricter. Choose minimist today only for legacy runtimes or deliberate loose passthrough parsing; existing usage is not worth panicking over, on 1.2.8.
Use it if
- You are writing a small script or internal tool and just need '--port 3000 --verbose' parsed into an object with zero ceremony
- You cannot use Node's built-in util.parseArgs because you must support Node older than 18.3, and you still want something tiny
- You need loose parsing on purpose: minimist accepts unknown flags without configuration, which suits passthrough wrappers around other CLIs
- Install size actually matters: 1.3KB and zero dependencies versus tens of packages for yargs
- You are on Node 18.3+ or 20+ and can use util.parseArgs: it is built in, typed, stricter, and removes the dependency entirely, which is the modern default for new code
- Your CLI needs help text, subcommands, validation, or type coercion rules: minimist has none of that and you will hand-roll it badly; commander or yargs exist for this
- You want strictness: minimist silently accepts any flag and guesses types, so typos like --prot 3000 become argv.prot with no error
- You want TypeScript ergonomics: types live in a separate @types/minimist package and the output is essentially 'any bag of keys'
Setup reality
npm install minimist, require or import the one function, done: CJS and works everywhere, no build questions. The care points are behavioral: numeric-looking values are auto-converted to numbers (version strings like 1.10 become 1.1 unless you list the flag in opts.string), single letters group ('-abc' is three booleans), and every unknown flag is accepted silently. Security history matters here too: two prototype-pollution advisories (fixed by 1.2.6) mean anything older in a lockfile still trips audits, so make sure resolution lands on 1.2.8.
Patterns
Parse process.argvbasic-parse
const minimist = require('minimist');
const argv = minimist(process.argv.slice(2));
// node app.js -x 3 --beep=boop foo bar
// { _: ['foo', 'bar'], x: 3, beep: 'boop' }Always slice(2) to drop the node binary and script path. Positionals land in argv._; everything else becomes a key, whether you expected it or not.
Pin flags as strings or booleansdeclare-types
const argv = minimist(process.argv.slice(2), {
string: ['version', 'port'],
boolean: ['verbose', 'force'],
});
// --version 1.10 stays '1.10' instead of becoming 1.1Without opts.string, numeric-looking values are converted: '1.10' becomes the number 1.1 and leading zeros vanish. Listing a flag in boolean also stops it swallowing the next argument.
Aliases and defaultsalias-default
const argv = minimist(process.argv.slice(2), {
alias: { p: 'port', v: 'verbose' },
default: { port: 3000, verbose: false },
});
// -p 8080 => argv.port === 8080 && argv.p === 8080Aliases populate both keys in the output, so destructure the long name and ignore the short one. Defaults apply only when the flag is completely absent.
Negation with --no-negated-flags
const argv = minimist(['--no-color']);
// { _: [], color: false }--no-foo yields foo: false automatically, no configuration needed. Combine with defaults ({ color: true }) to give users an off switch.
Pass arguments through after --double-dash-passthrough
const argv = minimist(process.argv.slice(2), { '--': true });
// node run.js --debug -- node child.js --port 3000
// argv._ = [], argv.debug = true
// argv['--'] = ['node', 'child.js', '--port', '3000']With '--': true the tail is separated into argv['--'] instead of mixed into argv._, which is exactly what wrapper CLIs that spawn other commands need.
Subcommand-style parsing with stopEarlysubcommand-stop-early
const argv = minimist(process.argv.slice(2), { stopEarly: true });
const [command, ...rest] = argv._;
if (command === 'build') {
const buildArgs = minimist(rest, { boolean: ['watch'] });
}stopEarly puts everything after the first positional into argv._ unparsed, letting you re-parse per subcommand. This is as far as minimist scales; past two subcommands, switch to commander.
Reject unknown flagsreject-unknown
const known = ['port', 'verbose', 'p', 'v', '_'];
const argv = minimist(process.argv.slice(2), {
alias: { p: 'port', v: 'verbose' },
unknown: (arg) => {
if (arg.startsWith('-')) {
console.error(`unknown option: ${arg}`);
process.exit(1);
}
return true; // keep positionals
},
});By default typos become new keys silently ('--prot 3000' just works, wrongly). The unknown callback is the only strictness mechanism minimist offers; returning false drops the arg.
Grouped short flags and attached valuesgrouped-short-flags
const argv = minimist(['-abc', '-n5']);
// { _: [], a: true, b: true, c: true, n: 5 }'-abc' expands to three booleans and '-n5' attaches the value, matching Unix convention. This also means a mistyped '-port' parses as four separate booleans, not a flag named port.
Make sure resolution lands on 1.2.8audit-lockfile-version
npm ls minimist
# force old transitive copies up via package.json:
{
"overrides": { "minimist": "^1.2.8" }
}The prototype-pollution advisories were fixed by 1.2.6, but ancient transitive pins (0.x, 1.2.0) still lurk in old lockfiles and light up npm audit; an override settles it.
The zero-dependency modern alternativebuiltin-parseargs
import { parseArgs } from 'node:util';
const { values, positionals } = parseArgs({
options: {
port: { type: 'string', short: 'p', default: '3000' },
verbose: { type: 'boolean', short: 'v' },
},
allowPositionals: true,
});Stable since Node 18.3/20: declared types, unknown flags throw, no dependency. For new code on modern Node this replaces minimist outright; note values are strings, never auto-numbers.
Alternatives
| Package | Registry | Pick it when |
|---|---|---|
| commander | npm | You are building a real CLI with subcommands, help text, and validation and want the most conventional API. |
| yargs | npm | You want rich parsing plus middleware, completion, and locale features and can accept a much heavier dependency tree. |
| arg | npm | You want minimist's size class but with explicit flag types declared up front instead of guessing. |