Después de años usando npm y yarn, cambié a pnpm hace un tiempo y no he vuelto atrás. En este post te explico las diferencias reales y por qué pnpm se ha convertido en mi package manager por defecto.
Comparativa rápida
| Característica | npm | yarn | pnpm |
|---|---|---|---|
| Velocidad | Lento | Rápido | Muy rápido |
| Espacio en disco | Alto (duplica deps) | Alto | Bajo (symlinks) |
| node_modules | Desordenado | Desordenado | Organizado |
| Monorepos | Workspaces | Workspaces | Workspaces nativos |
| Lockfile | package-lock.json | yarn.lock | pnpm-lock.yaml |
El problema con npm y yarn
Duplican todo
Imagina que tienes 10 proyectos que usan React 19. Con npm o yarn:
proyecto-1/node_modules/react/ → 2.5 MB
proyecto-2/node_modules/react/ → 2.5 MB
...
proyecto-10/node_modules/react/ → 2.5 MB
Total: 25 MB solo para React
Cada proyecto tiene su propia copia. Multiplica esto por todas tus dependencias y proyectos.
Permiten importar cosas que no instalaste
npm y yarn mezclan todas las dependencias en node_modules, incluyendo las dependencias de tus dependencias:
// Tu package.json NO tiene "lodash"
// Pero react-scripts sí lo usa internamente
import _ from "lodash"; // ¡Funciona! (pero no debería)
Esto se llama "dependencia fantasma". Tu código funciona hoy, pero si mañana react-scripts deja de usar lodash, tu app se rompe sin que hayas tocado nada.
Cómo pnpm resuelve esto
Content-addressable store
pnpm guarda todas las dependencias en un store global (~/.pnpm-store). Cada versión de cada paquete existe una sola vez:
~/.pnpm-store/
├── react@19.0.0/
├── react@18.3.1/
├── typescript@5.8.0/
└── ...
Tus proyectos usan symlinks (enlaces simbólicos) a este store:
proyecto-1/node_modules/react → ~/.pnpm-store/react@19.0.0
proyecto-2/node_modules/react → ~/.pnpm-store/react@19.0.0
Solo puedes usar lo que instalaste
pnpm organiza node_modules de forma que solo puedes importar lo que está en tu package.json. Si intentas usar una dependencia fantasma:
import _ from "lodash"; // ❌ Error: Cannot find module 'lodash'
pnpm te obliga a instalarla explícitamente:
pnpm add lodash
Velocidad real
Benchmark instalando las dependencias de un proyecto React típico:
# Proyecto con ~50 dependencias
npm install → 45 segundos
yarn install → 28 segundos
pnpm install → 12 segundos
Instalación
# Con npm
npm install -g pnpm
# Con Homebrew (macOS)
brew install pnpm
# Con corepack (recomendado, viene con Node 16+)
corepack enable
corepack prepare pnpm@latest --activate
Comandos equivalentes
| npm | yarn | pnpm |
|---|---|---|
npm install | yarn | pnpm install |
npm install pkg | yarn add pkg | pnpm add pkg |
npm install -D pkg | yarn add -D pkg | pnpm add -D pkg |
npm uninstall pkg | yarn remove pkg | pnpm remove pkg |
npm run dev | yarn dev | pnpm dev |
npx create-next-app | yarn create next-app | pnpm create next-app |
Migrar de npm/yarn a pnpm
Es simple:
# 1. Elimina node_modules y lockfile anterior
rm -rf node_modules package-lock.json yarn.lock
# 2. Instala con pnpm
pnpm install
Esto genera pnpm-lock.yaml. Commitea este archivo y elimina el lockfile anterior de git.
¿Cuándo NO usar pnpm?
Hay algunos casos donde podrías tener problemas:
- Proyectos legacy que dependen de poder importar dependencias no declaradas
- Algunas herramientas que no manejan bien symlinks (cada vez menos común)
Conclusión
pnpm resuelve problemas reales:
- Ahorra espacio → Un store global con symlinks
- Es más rápido → Instalaciones paralelas y caché eficiente
- Es más seguro → No puedes importar dependencias fantasma
- Monorepos nativos → Sin configuración extra
Si todavía usas npm o yarn, dale una oportunidad a pnpm. La migración es simple y los beneficios son inmediatos.