pnpm vs npm
Las diferencias prácticas entre pnpm y npm — cómo instalan paquetes, gestionan el espacio en disco, manejan lockfiles, y cuándo elegir uno u otro.
Recipe
Tarjeta de receta de referencia rápida — lista para copiar y pegar.
# Instalar pnpm (requiere Node.js 18.12+)
corepack enable
corepack prepare pnpm@latest --activate
# O instalar vía npm
npm install -g pnpm
# Verificar
pnpm --version
# Comandos comunes — lado a lado
npm install # pnpm install
npm install react # pnpm add react
npm install -D vitest # pnpm add -D vitest
npm uninstall react # pnpm remove react
npm run dev # pnpm dev (o pnpm run dev)
npm test # pnpm test
npx create-next-app # pnpm create next-app (o pnpm dlx create-next-app)Cuándo usarlo: Cuando inicies un nuevo proyecto o evalúes si cambiar de npm a pnpm. Entender los tradeoffs te ayuda a tomar una decisión informada en lugar de cambiar por hype.
Deep Dive
Cómo npm instala paquetes
npm usa una estructura node_modules plana. Cuando ejecutas npm install, hace lo siguiente:
- Lee
package.jsonpara las dependencias directas. - Resuelve el árbol completo de dependencias (dependencias de dependencias).
- Eleva tantos paquetes como sea posible al nivel superior de
node_modules/para reducir duplicación. - Escribe
package-lock.jsonpara fijar versiones exactas.
node_modules/
react/
react-dom/
scheduler/ # dependencia de react-dom, elevada al nivel superior
loose-envify/ # dependencia transitiva, también elevada
El problema con la elevación: tu código puede hacer import de paquetes que no están en tu package.json porque resulta que están elevados. Esto se llama phantom dependencies — tu código funciona por accidente hasta que alguien elimina el paquete que trajo la dependencia transitiva.
Cómo pnpm instala paquetes
pnpm usa un almacén de contenido direccionable y symlinks. Cuando ejecutas pnpm install, hace lo siguiente:
- Descarga paquetes a un almacén global (
~/.local/share/pnpm/store/en macOS/Linux). - Crea un almacén virtual dentro de
node_modules/.pnpm/con hard links al almacén global. - Crea symlinks en
node_modules/que apuntan solo a tus dependencias directas.
node_modules/
react -> .pnpm/react@19.1.0/node_modules/react
react-dom -> .pnpm/react-dom@19.1.0/node_modules/react-dom
.pnpm/
react@19.1.0/
node_modules/
react/ # hard link al almacén global
react-dom@19.1.0/
node_modules/
react-dom/ # hard link al almacén global
scheduler/ # symlink a .pnpm/scheduler@.../
Este layout significa:
- No puedes importar paquetes que no declaraste en
package.json— sin phantom dependencies. - Cada versión de un paquete se almacena una sola vez en disco en todos tus proyectos.
node_moduleses más pequeño e las instalaciones son más rápidas porque los archivos se vinculan, no se copian.
Diferencias clave
| Característica | npm | pnpm |
|---|---|---|
| Estructura de node_modules | Plana, elevada | Vinculada con symlinks, estricta |
| Uso de disco | Copia completa por proyecto | Almacén direccionable por contenido, hard links |
| Phantom dependencies | Permitidas (elevación) | Bloqueadas por defecto |
| Velocidad de instalación | Moderada | Más rápida (vinculación en lugar de copias) |
| Lockfile | package-lock.json | pnpm-lock.yaml |
| Soporte de monorepo | Workspaces (npm 7+) | Workspaces + pnpm-workspace.yaml |
| Se envía con Node.js | Sí | No (instalar por separado o vía Corepack) |
| Equivalente a npx | npx | pnpm dlx |
| Atajo para ejecutar scripts | npm run dev | pnpm dev |
| Manejo de peer dependencies | Auto-instaladas (npm 7+) | Estricto — advierte o genera error en pares faltantes |
| Soporte de Corepack | n/a (incluido) | Sí — "packageManager": "pnpm@9.x" en package.json |
Ahorro de espacio en disco
Con npm, si tienes 10 proyectos que usan React 19, React se copia 10 veces. Con pnpm, React 19 se almacena una vez en el almacén global y se vincula mediante hard link en cada proyecto. En una máquina con muchos proyectos, pnpm puede ahorrar gigabytes de espacio en disco.
# Ver cuánto espacio está usando el almacén de pnpm
pnpm store status
# Limpiar paquetes no referenciados del almacén
pnpm store pruneVelocidad de instalación
pnpm es consistentemente más rápido que npm por varias razones:
- Hard links en lugar de copias de archivo.
- Descargas paralelas con solicitudes de red concurrentes.
- Almacén direccionable por contenido significa que los paquetes descargados previamente están disponibles instantáneamente.
Los benchmarks típicos muestran pnpm 2-3 veces más rápido que npm en instalaciones en frío y significativamente más rápido en instalaciones en caliente (cuando los paquetes ya están en el almacén).
Rigidez y seguridad
El layout estricto de node_modules de pnpm detecta errores reales:
// Esto funciona con npm (phantom dependency) pero falla con pnpm:
import chalk from 'chalk';
// Error: chalk no está listado en package.jsonSi tu código solo funciona por la elevación de npm, pnpm expondrá la dependencia faltante inmediatamente. Esta es una característica, no un error — significa que tu package.json es una descripción precisa de lo que tu proyecto realmente usa.
Soporte de monorepo
Tanto npm como pnpm soportan workspaces, pero la implementación de pnpm es más madura:
# pnpm-workspace.yaml
packages:
- 'apps/*'
- 'packages/*'# Ejecutar un comando en un workspace específico
pnpm --filter @myapp/web dev
# Instalar una dependencia en un workspace específico
pnpm --filter @myapp/web add zod
# Ejecutar un comando en todos los workspaces
pnpm -r buildEl flag --filter de pnpm es más poderoso que el flag --workspace de npm, soportando patrones glob, filtrado basado en dependencias, y filtrado basado en cambios desde commit.
Comparación de comandos
| Tarea | npm | pnpm |
|---|---|---|
| Instalar todas las deps | npm install | pnpm install |
| Agregar un paquete | npm install zod | pnpm add zod |
| Agregar una dev dep | npm install -D vitest | pnpm add -D vitest |
| Eliminar un paquete | npm uninstall zod | pnpm remove zod |
| Ejecutar un script | npm run dev | pnpm dev |
| Ejecutar tests | npm test | pnpm test |
| Ejecutar un binario | npx create-next-app | pnpm dlx create-next-app |
| Actualizar deps | npm update | pnpm update |
| Auditoría de vulnerabilidades | npm audit | pnpm audit |
| Listar instalados | npm ls | pnpm ls |
| Instalación global | npm install -g tsx | pnpm add -g tsx |
Migrar de npm a pnpm
# 1. Instalar pnpm
corepack enable
corepack prepare pnpm@latest --activate
# 2. Eliminar artefactos de npm
rm -rf node_modules package-lock.json
# 3. Instalar con pnpm
pnpm install
# 4. (Opcional) Fijar la versión de pnpm en package.json
# Agregar: "packageManager": "pnpm@9.15.4"
# 5. Actualizar scripts — npm run -> pnpm
# Actualizar configuración de CI (GitHub Actions, etc.)La migración es generalmente indolora. Si falla, casi siempre se debe a phantom dependencies — paquetes que tu código importa pero que faltan en package.json. Corrígelas agregando explícitamente los paquetes faltantes.
Cuándo usar npm
- Quieres cero configuración. npm se envía con Node.js. Nada extra que instalar.
- Estás siguiendo un tutorial. La mayoría de tutoriales y documentación usan comandos npm. Traducir a pnpm es trivial pero añade fricción al aprender.
- Tu equipo usa npm y no hay problemas. Cambiar package managers a mitad del proyecto tiene un costo. Si npm está funcionando bien, no hay razón urgente para cambiar.
- El almacenamiento en caché de CI ya está optimizado para npm. Algunos proveedores de CI tienen mejor almacenamiento en caché incorporado para
node_modulesypackage-lock.json.
Cuándo usar pnpm
- Trabajas en muchos proyectos. El ahorro de espacio en disco es sustancial.
- Quieres corrección estricta de dependencias. Sin phantom dependencies significa menos sorpresas en producción.
- Ejecutas un monorepo. El soporte de workspace y filtrado de pnpm es de primera categoría.
- La velocidad de instalación importa. Instalaciones más rápidas significan CI más rápido e incorporación de desarrolladores más rápida.
- Quieres forzar un package manager específico. Corepack +
"packageManager"enpackage.jsonasegura que todos usen la misma herramienta y versión.
Gotchas
- Phantom dependencies se rompen en la migración. Si tu código importa un paquete que no está en
package.json, funciona con npm pero falla con pnpm. La solución es agregar el paquete faltante apackage.json— esto es lo correcto de todas formas. - Algunos paquetes asumen
node_modulesplano. Paquetes antiguos que usan trucos derequire.resolveo suben el árbol de directorios pueden fallar con el layout vinculado mediante symlinks de pnpm. La solución alternativa esnode-linker=hoisteden.npmrc, pero esto derrotaría la rigidez de pnpm. - El formato del lockfile es diferente. npm usa
package-lock.json(JSON). pnpm usapnpm-lock.yaml(YAML). No puedes usar ambos — elige uno y agrega el otro a.gitignore. npxno existe en pnpm. Usapnpm dlxen su lugar. Ejemplo:pnpm dlx create-next-appen lugar denpx create-next-app.- Rigidez de peer dependencies. pnpm es más estricto sobre peer dependencies que npm. Si un paquete espera
reactcomo peer dependency y no la has instalado, pnpm advierte o genera error. Soluciona instalando la peer dependency. - La configuración de CI es diferente. GitHub Actions y otros proveedores de CI necesitan
pnpm/action-setupo Corepack para instalar pnpm antes de ejecutarpnpm install. - Ubicación del almacén global. El almacén global de pnpm puede crecer bastante con el tiempo. Ejecuta
pnpm store pruneperiódicamente para limpiar paquetes que ya no son referenciados por ningún proyecto.
Alternativas
| Herramienta | Fortalezas | Debilidades |
|---|---|---|
| npm | Se envía con Node.js, soporte más amplio del ecosistema | Elevación plana, phantom deps, instalaciones más lentas |
| pnpm | Rápido, estricto, eficiente en disco, gran soporte de monorepo | Paso de instalación adicional, más estricto puede romper paquetes heredados |
| Yarn Classic (1.x) | Estable, ampliamente usado | Modo mantenimiento, problemas similares de elevación como npm |
| Yarn Berry (3+) | Plug'n'Play, cero-installs | Curva de aprendizaje pronunciada, problemas de compatibilidad, PnP puede confundir herramientas |
| Bun | Instalaciones extremadamente rápidas, runtime + bundler | Más nuevo, no 100% compatible con Node.js, ecosistema más pequeño |
FAQs
¿Puedo usar pnpm y npm en el mismo proyecto?
No deberías. Cada uno tiene su propio formato de lockfile (package-lock.json vs pnpm-lock.yaml) y estructura de node_modules. Elige uno y confirma solo su lockfile. Agrega el lockfile del otro a .gitignore.
¿Funciona pnpm con Next.js?
Sí. Next.js funciona con pnpm inmediatamente. pnpm create next-app genera un nuevo proyecto. La única salvedad es que algunos ejemplos de Next.js usan comandos npm en sus READMEs — simplemente sustituye con equivalentes de pnpm.
¿Qué es Corepack?
Corepack es una herramienta incluida con Node.js (18.17+) que gestiona versiones de package manager. Cuando establecer "packageManager": "pnpm@9.15.4" en package.json, Corepack asegura que todos usen exactamente esa versión. Habilítalo con corepack enable.
¿Es pnpm más rápido que npm?
Sí, en la mayoría de benchmarks. pnpm es 2-3 veces más rápido en instalaciones en frío y aún más rápido en instalaciones en caliente (cuando los paquetes ya están en el almacén global). La velocidad proviene de vincular archivos con hard links en lugar de copiarlos y de solicitudes de red paralelas.
¿Qué son phantom dependencies?
Paquetes que tu código importa pero que no están listados en tu package.json. Funcionan con npm porque la elevación hace que las dependencias transitivas sean accesibles en el nivel superior. pnpm bloquea esto por defecto, lo que detecta errores reales — tu código debería solo importar paquetes de los que explícitamente dependes.
¿Cómo ejecuto un comando único con pnpm (como npx)?
Usa pnpm dlx. Por ejemplo: pnpm dlx create-next-app en lugar de npx create-next-app. El comando dlx descarga y ejecuta el paquete sin instalarlo permanentemente.
¿Puedo cambiar de vuelta a npm desde pnpm?
Sí. Elimina node_modules y pnpm-lock.yaml, luego ejecuta npm install. Esto genera un package-lock.json fresco. Si tenías phantom dependencies que pnpm detectó, "funcionarán" silenciosamente de nuevo bajo npm.
¿Soporta pnpm registros privados?
Sí. Configura el registro en .npmrc de la misma forma que lo harías para npm: registry=https://your-registry.example.com/. pnpm lee archivos .npmrc.
¿Y Yarn? ¿Cómo se compara?
Yarn Classic (1.x) es similar a npm con elevación plana. Yarn Berry (3+) usa Plug'n'Play que evita node_modules completamente pero tiene problemas de compatibilidad con algunos paquetes. pnpm está en el medio — estricto y rápido sin los dolores de cabeza de compatibilidad de PnP.
¿Debería cambiar mi proyecto existente a pnpm?
Si npm está funcionando bien y tu equipo está cómodo, no hay urgencia. Considera cambiar si estás iniciando un nuevo proyecto, ejecutando un monorepo, o experimentando instalaciones lentas y presión de espacio en disco. La migración es generalmente directa.