Hay decisiones en el desarrollo de software que parecen triviales hasta que te explotan en la cara. Qué package manager usar es una de esas. Yo las pagué todas: proyectos con node_modules de 4GB, deploys que fallaban por conflictos de versiones que "no deberían existir", monorepos que tardaban 8 minutos en instalarse en CI. Todo eso me hizo obsesionarme con este tema.
Así que vamos directo al hueso: pnpm vs npm vs yarn vs bun — qué son, qué hacen diferente, cuándo usar cada uno, y cuál ganó mi corazón (y mi .zshrc).
Un poco de historia para que entiendas por qué existe este caos
npm llegó en 2010 pegado a Node.js. Era la única opción y, francamente, era un desastre. El node_modules flat que conocemos hoy ni existía — en las versiones viejas tenías árbol anidado infinito, carpetas dentro de carpetas que llegaban a rutas tan largas que Windows directamente se rendía. En serio.
Yarn apareció en 2016, creado por Facebook (ahora Meta) en colaboración con Google y otros. Fue una bocanada de aire fresco: instalaciones paralelas, lockfile determinístico, cache local. npm tardó años en ponerse al día.
pnpm llegó también por esa época pero tardó más en tomar tracción. Y Bun... Bun es el newcomer que llegó en 2023 a decir que todos los demás son lentos y tiene cierta razón.
npm: el que ya tenés instalado
Lo bueno: Viene con Node. Sin instalación extra, sin explicarle nada a nadie. Para un proyecto pequeño o para onboardear a alguien nuevo es imbatible en simplicidad.
Lo malo: Sigue siendo el más lento de los cuatro en instalaciones en frío. El node_modules es un monstruo flat que duplica paquetes alegremente. En un monorepo mediano vi node_modules llegar a 3.8GB. Eso no es normal. Eso es un problema.
La versión 7 trajo workspaces, la 8 mejoró bastante el performance, y npm hoy en día es decente. Pero "decente" no es suficiente cuando existían mejores alternativas hace años.
Mi experiencia real: En 2021 arranqué un proyecto con npm por defecto. A los tres meses el CI tardaba 6 minutos solo en el npm install. Migré a pnpm en un viernes a la tarde (error mío, nunca migrés nada importante un viernes) y el lunes el CI tardaba 90 segundos. Eso me marcó.
Cuándo usarlo: Cuando el proyecto es chico, cuando el equipo no quiere fricción de setup, o cuando trabajás con herramientas que tienen bugs conocidos con pnpm (sí, existen, aunque cada vez menos).
Yarn: el que prometía mucho y se complicó
Yarn clásico (v1) fue revolucionario en su momento. Lockfile determinístico, caché que realmente funcionaba, parallelismo. npm tardó literalmente años en igualar esas features.
Pero después llegó Yarn Berry (v2 en adelante) y todo se complicó. Introdujeron Plug'n'Play (PnP): en lugar de node_modules, un sistema de resolución propio donde los paquetes están en archivos .zip y un loader los resuelve en runtime. La teoría es preciosa. La práctica es otro tema.
Probé Yarn Berry en un proyecto Next.js y fue una tarde entera de debuggear por qué ciertos paquetes no levantaban. Algunos tools del ecosistema simplemente no entienden el modelo PnP. Terminé en nodeLinker: node-modules en el .yarnrc.yml, que básicamente es usar Yarn Berry actuando como Yarn clásico. ¿Para qué, entonces?
Lo bueno de Yarn: La DX cuando funciona es muy linda. Los workspaces de Yarn son muy maduros. El equipo de Yarn lleva años puliendo esto.
Lo malo: La fragmentación entre v1 y v2/v3/v4 es un quilombo. Si buscás un error en Stack Overflow, el 60% de las respuestas son para la versión equivocada. Y PnP, aunque brillante conceptualmente, genera fricción real.
Cuándo usarlo: Yarn clásico (v1) en proyectos legados que ya lo usan y no vale la pena migrar. Yarn Berry si estás dispuesto a invertir tiempo en entender PnP y tu equipo está alineado.
pnpm: mi favorito sin discusión
Acá es donde me pongo intenso, así que aguantame.
pnpm resuelve el problema fundamental del package management de Node de una manera elegante: el content-addressable store. En lugar de copiar paquetes en cada node_modules, usa hard links a un store global en tu máquina. lodash instalado en 47 proyectos distintos ocupa espacio de disco una sola vez. El node_modules de cada proyecto son mayormente symlinks y hard links.
Esto tiene consecuencias reales:
- Velocidad: Primera instalación comparable a npm/yarn. Segunda instalación y en adelante: ridículamente rápida.
- Espacio en disco: Tengo quizás 200 proyectos en esta máquina. Si usara npm serían cientos de GB. Con pnpm el store global ocupa ~15GB para todo.
- Correctitud: pnpm es estricto con las dependencias. No podés acceder a un paquete que no declaraste en tu
package.json. Esto parece una molestia hasta que te das cuenta de que npm/yarn te dejan acceder a dependencias transitivas silenciosamente — una bomba de tiempo.
Los workspaces de pnpm son los mejores del ecosistema, punto. El archivo pnpm-workspace.yaml es simple, el hoisting configurable, y el comando pnpm -r para correr scripts en todos los packages es una joya.
Mi experiencia real: Hoy uso pnpm en absolutamente todos mis proyectos personales y profesionales. El comando que más escribo después de git es probablemente pnpm install. Tuve exactamente un problema de compatibilidad en dos años: una librería vieja que asumía hoisting de npm. Lo resolví en 10 minutos con .npmrc ajustado.
Lo malo de pnpm: La instalación inicial es un paso extra. Algunos proyectos open source con configs de npm legacy pueden dar dolores de cabeza. Y el store global puede crecer mucho si no hacés pnpm store prune de vez en cuando (yo lo tengo en un cron).
Cuándo usarlo: Casi siempre. Especialmente en monorepos. Especialmente si te importa el espacio en disco. Especialmente si querés que tus dependencias estén correctamente declaradas.
Bun: el que llegó a romper todo
Bun no es solo un package manager — es un runtime completo (reemplazo de Node), un bundler, un test runner, y un transpiler. Pero acá hablamos de su faceta como package manager.
Los números: Bun install es absurdamente rápido. Hablo de instalaciones en frío de proyectos medianos en 2-3 segundos. Lo que npm hace en 45 segundos, Bun lo hace en 3. Está escrito en Zig, usa su propio runtime, y tiene un caché binario que hace que las instalaciones repetidas sean casi instantáneas.
Lo probé en un proyecto Next.js y funcionó perfecto. El lockfile (bun.lockb) es binario, lo cual es raro conceptualmente pero funciona. Los workspaces están soportados. La compatibilidad con el ecosistema npm es muy buena.
Pero acá viene mi hesitación: Bun como runtime todavía tiene edge cases donde el comportamiento difiere de Node. Si usás Bun solo como package manager (con Node como runtime), eso desaparece — pero entonces estás instalando un tool enorme para usar solo una fracción.
El ecosistema de Bun maduró muchísimo en 2024. Para 2025 es una opción real y seria. Pero yo todavía no migré mis proyectos productivos porque el riesgo/beneficio no cierra para mí. La velocidad de pnpm con caché es más que suficiente, y el modelo mental de Bun como "todo en uno" todavía me genera incertidumbre en deployments complejos.
Cuándo usarlo: Si arrancás un proyecto nuevo y querés experimentar. Si el performance de instalación es crítico para vos (¿monorepo enorme en CI sin caché?). Si sos el tipo de persona que le gusta estar en la vanguardia y bancarse algún rough edge.
La tabla que todos quieren
| npm | Yarn | pnpm | Bun | |
|---|---|---|---|---|
| Velocidad (frío) | Lento | Medio | Rápido | Muy rápido |
| Velocidad (caché) | Medio | Rápido | Muy rápido | Muy rápido |
| Espacio en disco | Mucho | Mucho | Poco | Poco |
| Monorepos | Básico | Bueno | Excelente | Bueno |
| Madurez | Alta | Alta | Alta | Media |
| Compatibilidad | Total | Alta | Alta | Alta |
| Strictness | No | No | Sí | No |
Mi recomendación final, sin rodeos
¿Proyecto nuevo, 2025? → pnpm. Sin dudarlo. La curva de aprendizaje es mínima (es casi idéntico a npm en la interfaz), los beneficios son inmediatos y reales, y el soporte del ecosistema es excelente.
¿Monorepo? → pnpm con workspaces. Es la mejor opción disponible hoy.
¿Querés vivir en el futuro? → Bun. Pero sabé que vas a ser el beta tester de algunas cosas.
¿Proyecto legado que ya tiene yarn.lock o package-lock.json? → No migrés por migrar. El lockfile es contrato. Si no tenés un motivo real de performance o correctitud, dejalo como está.
npm puro en 2025 sin una razón específica: No. Ya no. Es como usar jQuery en un proyecto nuevo — funciona, pero hay mejores opciones y vos lo sabés.
El ecosistema JavaScript tiene sus mil problemas, pero en package management llegamos a un punto donde tenemos opciones genuinamente buenas. Aprovechalo. Yo tardé demasiado en salir de npm por inercia, y esos 6 minutos de CI en 2021 me los voy a cobrar de alguna forma.
Comentarios (0)
Deja un comentario
Artículos Relacionados
Metí un LLM chico adentro de una app Next.js y esto fue lo que aprendí
Reproducí el experimento del LLM tiny que explotó en Show HN: Gemma corriendo en el browser, sin API keys, desde mi stack habitual. Acá está todo lo que salió mal — y lo poco que salió bien.
TypeScript: los patrones que realmente uso todos los días
Discriminated unions, branded types, generics avanzados y cómo pienso en tipos cuando programo. No es un tutorial académico — es lo que realmente uso en producción después de años de batallar con TypeScript.
Docker para desarrolladores Node.js: de cero a producción sin morir en el intento
Me llevó tres Dockerfiles rotos, dos servidores caídos en producción y una noche sin dormir entender cómo funciona Docker con Node.js de verdad. Acá te cuento todo lo que aprendí para que vos no pases por lo mismo.