Qué es npm en realidad
npm son tres cosas empaquetadas bajo un mismo nombre. Por un lado es un registro: una base de datos pública enorme de paquetes de JavaScript alojada en npmjs.com. Por otro, es una herramienta de línea de comandos que viene incluida con Node.js y sirve para instalar y gestionar esos paquetes. Y, por último, es una especificación (el formato package.json) que describe lo que necesita tu proyecto.
Cuando ejecutas npm install express, la CLI se conecta al registro, descarga express junto con todas sus dependencias, coloca los archivos dentro de una carpeta llamada node_modules y deja registrado el paquete y su versión en tu package.json. Ese es el ciclo completo.
Si ya tienes Node.js instalado, también tienes npm. Compruébalo:
node --version
npm --version
Si ambos muestran una versión, ya estás listo.
Iniciar un proyecto con npm init
Todo proyecto de npm necesita un package.json. Ese archivo es el manifiesto: contiene el nombre del proyecto, su versión, los scripts y las dependencias. La forma más rápida de crearlo es con npm init -y, que acepta todos los valores por defecto:
mkdir my-app
cd my-app
npm init -y
Esto imprime algo como:
{
"name": "my-app",
"version": "1.0.0",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}
Si omites -y, npm te irá preguntando campo por campo de forma interactiva. Sea como sea, acabarás con un package.json: el archivo al que se engancha todo lo demás. Veremos sus campos en detalle en la siguiente página.
Cómo instalar un paquete con npm
Cuando ya tengas tu package.json, instala cualquier paquete con npm install (o npm i, su forma corta):
npm install lodash
Ocurren tres cosas:
- npm descarga
lodashy sus dependencias dentro denode_modules/. - Añade
"lodash": "^4.17.21"(o la versión más reciente que haya) a la seccióndependenciesdelpackage.json. - Genera un
package-lock.jsondonde queda registrada la versión exacta de cada paquete del árbol de dependencias.
Ya puedes usarlo:
La llamada a require (o import si trabajas con un proyecto ESM) localiza el paquete dentro de node_modules. No hace falta que escribas la ruta: del resto se encarga el resolver de módulos de Node.
dependencies vs devDependencies
No todos los paquetes son imprescindibles cuando tu app corre en producción. Los frameworks de testing, los linters y los bundlers solo se usan mientras desarrollas. Para instalarlos, usa --save-dev (o su forma corta -D):
npm install --save-dev jest
npm install -D eslint prettier
Estos se registran en devDependencies en lugar de dependencies:
{
"dependencies": {
"lodash": "^4.17.21"
},
"devDependencies": {
"jest": "^29.7.0",
"eslint": "^8.57.0",
"prettier": "^3.2.5"
}
}
En un servidor de producción, npm install --omit=dev se salta por completo la sección de desarrollo, lo que hace la instalación más ligera y rápida. Acertar con esta separación importa más de lo que parece: un webpack mal colocado en dependencies infla cada despliegue a producción.
Instalar todas las dependencias de golpe
Cuando clonas un repositorio que ya trae un package.json, no hace falta ir paquete por paquete. Basta con ejecutar:
npm install
Sin argumentos, npm lee package.json (y respeta las versiones exactas fijadas en package-lock.json) para instalar todo el árbol de dependencias dentro de node_modules. Es lo primero que ejecutas al clonar un proyecto.
Por eso mismo node_modules va en tu .gitignore. Se puede regenerar desde el lockfile, ocupa muchísimo espacio y cambia cada vez que alguien corre npm install. Lo que subes al repo es package.json y package-lock.json; que cada quien genere su propio node_modules.
Actualizar paquetes con npm
Con npm outdated ves qué dependencias se quedaron atrás:
npm outdated
Verás una tabla con las columnas Current, Wanted y Latest. Wanted es la versión más reciente que permite el rango definido en tu package.json (por ejemplo, con ^4.17.21 acepta cualquiera por debajo de 5.0.0). Latest es la última versión publicada, que puede ser un major al que todavía no te hayas sumado.
Para actualizar dentro del rango permitido:
npm update
Para saltar directamente a la última versión disponible (incluyendo cambios de versión mayor), vuelve a instalar el paquete con @latest:
npm install lodash@latest
Los saltos de versión mayor pueden romper tu código — para eso está la numeración, para avisarte. Antes de dar ese salto, revisa el changelog.
Desinstalar paquetes
Eliminar un paquete funciona igual de fácil:
npm uninstall lodash
Así se elimina de node_modules y se borra la entrada del package.json. Agrega -D si era una dependencia de desarrollo (npm lo detecta solo, pero ser explícito evita sorpresas en los scripts).
npm global vs local
Casi todas las instalaciones deberían ser locales: ancladas a un proyecto dentro de su node_modules. La excepción son las herramientas de línea de comandos que quieres tener disponibles en cualquier parte:
npm install -g typescript
npm install -g http-server
Instalar un paquete de forma global coloca la herramienta en una ubicación del sistema y añade su entrada bin al PATH, de modo que puedes ejecutar tsc o http-server desde cualquier carpeta. El problema es que las instalaciones globales no quedan registradas por proyecto y suelen desincronizarse entre máquinas.
Para comandos puntuales, una alternativa mucho más práctica es npx, que viene incluido con npm:
npx create-react-app my-app
npx prettier --write .
npx ejecuta un paquete sin instalarlo globalmente: lo descarga en el momento, lo corre y listo. Para herramientas que vas a usar una sola vez, es mucho más limpio que dejarlas instaladas como paquete global.
Chuleta mínima de comandos npm
Los comandos que de verdad vas a usar en el día a día:
npm init -y # create package.json
npm install # install everything in package.json
npm install <pkg> # add a runtime dependency
npm install -D <pkg> # add a dev dependency
npm install -g <pkg> # install a CLI tool globally
npm uninstall <pkg> # remove a dependency
npm outdated # see what's out of date
npm update # update within allowed ranges
npm install <pkg>@latest # jump to the newest version
npm run <script> # run a script from package.json
npx <pkg> # run a package without installing it
Con esto ya tienes lo esencial de npm. Lo demás —publicar paquetes, workspaces, paquetes con scope— lo irás aprendiendo cuando te haga falta.
Qué hay realmente dentro de node_modules
Un último modelo mental. node_modules es una carpeta más o menos plana que contiene todos los paquetes de los que depende tu proyecto, más todo aquello de lo que dependen esos paquetes, de forma transitiva. Instalas un paquete y puedes acabar arrastrando cien: es lo normal. npm deduplica siempre que puede, así que si dos paquetes dependen de la misma versión de lodash, comparten una única copia.
El lockfile (package-lock.json) registra la versión exacta que se resolvió para cada uno de esos paquetes. Eso es lo que hace que las builds sean reproducibles: dos personas ejecutando npm install con el mismo lockfile obtienen árboles de dependencias idénticos byte a byte, incluso meses después.
Trata node_modules como si fuera una salida generada. Nunca toques sus archivos a mano: tus cambios se perderán la próxima vez que alguien instale.
Siguiente paso: package.json
package.json es el archivo que npm lee y reescribe constantemente entre bambalinas. Dominar sus campos —scripts, main, type, los rangos de versiones, engines— es lo que convierte a npm de una caja negra en una herramienta que controlas tú. Vamos a ello.
Preguntas frecuentes
¿Qué es npm?
npm es el gestor de paquetes por defecto de Node.js. Viene instalado con Node, aloja un registro público enorme de paquetes de JavaScript y te da una herramienta de línea de comandos para instalarlos, actualizarlos y publicarlos. Cuando ejecutas npm install lodash, npm descarga lodash desde el registro a la carpeta node_modules y lo añade a tu package.json.
¿Qué diferencia hay entre dependencies y devDependencies?
Las dependencies son los paquetes que tu app necesita para funcionar en producción, como express o react. Las devDependencies sólo hacen falta mientras desarrollas o compilas: test runners, bundlers, linters... Estas últimas se instalan con npm install --save-dev <paquete> (o -D). En producción, npm install --omit=dev se salta las devDependencies.
¿Debería subir node_modules a git?
No. La carpeta node_modules puede ocupar cientos de megas sin despeinarse y es totalmente reproducible a partir de package.json + package-lock.json. Añádela al .gitignore y sube el lockfile en su lugar. Cualquiera que clone tu repo ejecuta npm install y obtiene exactamente el mismo árbol de dependencias.
¿Qué diferencia hay entre instalar con npm global y local?
Una instalación local (npm install <paquete>) coloca el paquete dentro del node_modules de tu proyecto y lo registra en package.json. Una instalación global (npm install -g <paquete>) lo instala a nivel de sistema, algo típico para herramientas de línea de comandos que quieres tener disponibles en cualquier sitio. Para las dependencias de un proyecto es mejor la instalación local, así cada proyecto mantiene sus versiones fijadas.