process.argv
Returns the command-line arguments the process was launched with, as an array of strings.
process.argv- Added in Node.js v0.1.27
Return value
string[]An array of strings: the executable path, the entry point path if one was provided, then any remaining command-line arguments.
process.argv is the raw argument vector. Index 0 is process.execPath — the absolute path of the Node binary — and index 1 is the absolute path of the entry point. Everything a user typed starts at index 2, which is why almost every CLI begins with process.argv.slice(2).
When to reach for it
Use it for small scripts and build steps where a full argument-parsing dependency is overkill, or as the input to util.parseArgs() for anything with flags, short options and positionals.
What trips people up
- Runtime flags are not in argv. Options aimed at Node itself, such as
--trace-warningsor--max-old-space-size, land inprocess.execArgv. Only arguments after the script path reachargv. - There is no argv[1] with
node -e. With inline evaluation there is no entry point, so user arguments start at index 1 andslice(2)silently drops the first one. - Everything is a string.
--port 8080gives you'8080'; nothing is coerced and nothing is validated. - npm swallows flags.
npm run build --watchpasses--watchto npm; you neednpm run build -- --watch.
Example
When to use it
- Accept a target file path for a one-off migration or codemod script.
- Read a --dry-run flag before a script performs destructive work.
- Feed process.argv.slice(2) into util.parseArgs() to build a small CLI.
- Log the exact command a failing CI job was invoked with.
Frequently asked questions
Why does process.argv start at index 2 for my arguments?
Because index 0 is the Node executable and index 1 is the absolute path of the script being run, so user arguments begin at index 2. The exception is `node -e '...'`, where no script path exists and the first user argument sits at index 1.
How do I pass arguments through npm run to my script?
Put a bare `--` between the npm script name and your arguments: `npm run build -- --watch`. Without the separator npm treats `--watch` as its own flag and it never reaches process.argv.
Why is my numeric argument a string?
process.argv is documented as `string[]`, so nothing is parsed or coerced for you. Convert with `Number(value)` and check the result with `Number.isFinite()`, since a bad argument yields `NaN` instead of throwing.
More examples
Parsing flags with util.parseArgs()
The output shows parseArgs (available since v18.3.0) splitting the same array three ways: `--out ./dump` becomes a typed value, the short `-v` expands to `verbose: true`, and the two bare filenames collect into `positionals`. An unknown flag makes parseArgs throw `ERR_PARSE_ARGS_UNKNOWN_OPTION` rather than being silently ignored, which is the main reason to prefer it over hand-rolled filtering.
const { parseArgs } = require('node:util');
// node backup.js --out ./dump -v notes.txt todo.txt
const { values, positionals } = parseArgs({
args: process.argv.slice(2),
options: {
out: { type: 'string', short: 'o', default: './backup' },
verbose: { type: 'boolean', short: 'v', default: false },
},
allowPositionals: true,
});
console.log('output directory:', values.out);
console.log('verbose:', values.verbose);
console.log('files:', positionals);
// output directory: ./dump
// verbose: true
// files: [ 'notes.txt', 'todo.txt' ]argv versus execArgv
The output shows where each part of the command line ends up. `--trace-warnings` appears only in `execArgv` because it was consumed by the runtime before the script started, while `--port 8080` reaches `argv`. `process.argv0` keeps the original argv[0] as the shell supplied it, which differs from the resolved `execPath` when the binary was invoked through a symlink or a custom name.
// Invoked as: node --trace-warnings server.js --port 8080
console.log('execPath :', process.argv[0]);
console.log('argv0 :', process.argv0);
console.log('entry point:', process.argv[1]);
console.log('user args :', process.argv.slice(2));
console.log('node flags :', process.execArgv);
// execPath : /usr/local/bin/node
// argv0 : node
// entry point: /srv/app/server.js
// user args : [ '--port', '8080' ]
// node flags : [ '--trace-warnings' ]A dry-run guard for a destructive script
The output shows the script reporting what it would do rather than doing it. Exiting with code 1 on missing arguments is what makes the script usable from a Makefile or CI step: a shell `&&` chain stops on the non-zero code, whereas printing usage and returning normally would let the pipeline continue as if the work had succeeded.
const args = process.argv.slice(2);
const dryRun = args.includes('--dry-run');
const targets = args.filter((a) => !a.startsWith('-'));
if (targets.length === 0) {
console.error('usage: node prune.js [--dry-run] <path...>');
process.exit(1);
}
for (const target of targets) {
if (dryRun) {
console.log(`would delete: ${target}`);
} else {
console.log(`deleting: ${target}`);
}
}
// node prune.js --dry-run cache/ tmp/
// would delete: cache/
// would delete: tmp/
Discussion