process.argv es un array con la línea de comandos que lanzó tu programa de Node.js. El índice 0 es la ruta al ejecutable de node, el índice 1 es la ruta a tu script, y tus propios argumentos empiezan en el índice 2. Así que process.argv.slice(2) te da exactamente lo que el usuario escribió después del nombre del archivo, siempre como strings.
Las dos primeras entradas son rutas completas, así que esto imprime solo su última parte (node e index.js), y luego [ 'Ada', '42', '--verbose' ]. Cambia la fila de argumentos a Grace 7 y vuelve a ejecutar: el array cambia con ella.
Qué entra en process.argv
La shell separa por espacios la línea que va después de node y le pasa los trozos a Node.js. Los flags escritos antes del nombre del archivo son para el propio Node.js, no para tu programa:
node --max-old-space-size=4096 index.js --port=8080
# process.argv.slice(2) is [ '--port=8080' ]
# process.execArgv is [ '--max-old-space-size=4096' ]
Las comillas agrupan palabras en un solo argumento ("Ada Lovelace" llega como un único string), y la shell expande patrones como *.txt a nombres de archivo antes de que Node.js los vea.
Obtener los argumentos con slice(2)
La mayoría de los scripts desestructuran los argumentos que esperan y les dan un valor por defecto:
Imprimió Hello, Ada: un argumento rellenó name, y greeting usó su valor por defecto. Añade Hi después de Ada en la fila de argumentos e imprime Hi, Ada; vacía la fila y obtienes Hello, world.
Los números llegan como strings
La shell no tiene tipos. Cada argumento es un string, así que la aritmética con ellos sale mal hasta que los conviertes:
a + b concatenó los strings en 75, y Number() dio 12. Una palabra que no es un número se convierte en NaN, así que compruébalo con Number.isNaN e imprime un mensaje de uso en lugar de seguir con un valor roto.
Parsear flags --nombre=valor a mano
Para un par de flags, basta con un bucle corto. Este convierte --port=8080 en port: '8080', un --verbose suelto en true, y deja todo lo demás como argumento posicional:
Imprimió {"port":"8080","verbose":true} y [ 'build', 'src' ], con port todavía como string. Este bucle no maneja flags cortos como -p ni un valor en el argumento siguiente (--port 8080); para eso, usa el parser integrado de abajo.
util.parseArgs, el parser integrado
Node.js 18.3 y posteriores incluyen util.parseArgs, que maneja flags largos y cortos, valores en el argumento siguiente, booleanos y valores por defecto:
const { parseArgs } = require('node:util');
// node index.js -p 8080 --verbose src
const { values, positionals } = parseArgs({
options: {
port: { type: 'string', short: 'p', default: '3000' },
verbose: { type: 'boolean', short: 'v' },
},
allowPositionals: true,
});
console.log(values); // [Object: null prototype] { port: '8080', verbose: true }
console.log(positionals); // [ 'src' ]
parseArgs lee process.argv.slice(2) por defecto. Lanza un error con una opción que no declaraste, lo que detecta erratas como --prot; pasa strict: false para aceptar flags desconocidos. Los tipos de opción son solo string y boolean, así que los números siguen necesitando Number(). values es un objeto sin prototipo, por eso se imprime con [Object: null prototype]; léelo como cualquier objeto.
Errores comunes
Leer process.argv[0] como el primer argumento. Es la ruta a node. Tu primer argumento es process.argv[2].
Olvidar que todo es un string. '10' > '9' es false, porque los strings se comparan carácter a carácter. Convierte primero.
Poner secretos en los argumentos. Las líneas de comandos aparecen en el historial de la shell y en las listas de procesos que otros usuarios de la máquina pueden leer. Pasa contraseñas y API keys mediante variables de entorno.
Preguntas frecuentes
¿Cómo paso argumentos a un script de npm?
Ponlos después de --: npm run start -- --port=4000. npm pasa todo lo que va después del -- a tu script, donde aparece en process.argv.slice(2).
¿Por qué process.argv[2] es undefined?
Porque el programa se lanzó sin ese argumento. Dale un valor por defecto (process.argv[2] ?? 'guest'), o imprime una línea de uso y termina con process.exit(1).
¿Uso yargs o commander en lugar de process.argv?
Para un script con pocos flags, util.parseArgs viene integrado y basta. Paquetes como commander y yargs añaden texto de ayuda, subcomandos y validación, y compensan cuando tu herramienta tiene varios comandos.