yarn en breve: Berry, Plug'n'Play y por qué no se impuso
La historia de yarn es la del progreso de todo el campo: Classic (2016) avergonzó a npm hasta forzarle el determinismo y la velocidad; Berry (2020) fue radical con Plug'n'Play, aboliendo node_modules a cambio de un mapa de resolución y zero-installs. Qué es PnP, qué compran los zero-installs, por qué la fricción de compatibilidad impidió que se impusiera, y por qué en 2026 el estándar del layout estricto es pnpm y no yarn.
La historia de yarn es, en miniatura, la historia del progreso de todo este campo. Yarn Classic apareció en 2016 y avergonzó a npm hasta obligarle a adoptar lockfiles y velocidad. Yarn Berry, en 2020, fue mucho más lejos con Plug’n’Play: abolir node_modules por completo y sustituirlo por un mapa de resolución. Sus ideas más ambiciosas —los zero-installs, un mapa en vez de un árbol de carpetas— eran técnicamente brillantes y el ecosistema las rechazó en gran medida. Esta lección explica qué es PnP, qué prometen los zero-installs y por qué en 2026 el estándar del layout estricto acabó siendo pnpm.
- Situar Yarn Classic y su papel histórico como aguijón de npm.
- Entender Plug’n’Play: sin node_modules, un mapa de resolución explícito.
- Definir los zero-installs y la promesa de clonar y ejecutar sin instalar.
- Explicar la fricción de compatibilidad que frenó a PnP y el estado en 2026.
Yarn Classic: el aguijón que despertó a npm
En 2016, con npm 3 aplanando árboles de forma no determinista y lento, Facebook publicó Yarn Classic, la línea 1.x. Traía tres cosas que hoy damos por sentadas: un yarn.lock que fijaba el árbol resuelto, descargas paralelizadas y una caché offline. Su mera existencia forzó a npm a reaccionar —package-lock.json llegó en npm 5, en 2017— y elevó el listón para todo el ecosistema.
Cumplido ese papel histórico, Yarn Classic quedó congelado en mantenimiento. Sus ideas se volvieron el mínimo común de todos los gestores, y el equipo redirigió su energía a una reescritura completa. La 1.x sigue funcionando, pero es legado que no conviene empezar a usar en 2026: cualquier proyecto nuevo que elija yarn debería ir a Berry.
Plug’n’Play: abolir node_modules
Yarn Berry —la 2.x en adelante— fue esa reescritura, con una tesis provocadora: si node_modules es la fuente de los males, elimínalo. Plug’n’Play (PnP) hace justo eso. En lugar de desplegar un árbol de carpetas, guarda los paquetes como archivos zip en .yarn/cache y genera un único archivo, .pnp.cjs, que es un mapa de resolución explícito: dado un paquete y una versión, dónde está su zip y qué otros paquetes tiene permitido resolver.
node_modules/ (miles de archivos, arbol en disco)
|
v
.pnp.cjs (un mapa: paquete + version -> ruta en el zip + deps permitidas)
.yarn/cache/ (paquetes comprimidos en zip)
Node no sabe leer ese mapa por sí solo, así que Berry parchea el resolvedor mediante un loader que consulta .pnp.cjs en vez de recorrer carpetas. Las ventajas son reales y notables: instalaciones sin el coste de escribir un árbol enorme, arranque más rápido porque no hay que hacer stat de miles de archivos, y resolución exacta. Las fantasmas son imposibles, porque el mapa es el contrato y solo autoriza lo que se declaró.
El modo de enlazado se elige en .yarnrc.yml, y ahí asoma la tensión que atravesó todo el proyecto: yarn terminó ofreciendo varias estrategias, incluida la de recrear el mismo node_modules que PnP nació para abolir.
nodeLinker: pnp # el modo estricto original de Berry
# nodeLinker: pnpm # arbol de symlinks al estilo pnpm
# nodeLinker: node-modules # la via de escape totalmente compatible
Zero-installs: clonar y ejecutar
Sobre PnP, Berry ofrece su idea más vistosa: los zero-installs. Como los paquetes son zips en .yarn/cache y toda la resolución cabe en .pnp.cjs, puedes versionar ambos en git. Quien clona el repositorio obtiene un proyecto listo para ejecutar sin paso de instalación: git clone y a correr, sin negociar con el registro ni desplegar node_modules.
Para arranques en frío de CI y para reproducibilidad total es genuinamente potente: el estado instalado es el estado versionado, sin ventana entre clonar y poder ejecutar. Pero tiene un coste que a muchos equipos les resultó inasumible.
Comprometer .yarn/cache mete binarios comprimidos en el historial de git. En proyectos con muchas dependencias eso hincha el repositorio, ensucia los diffs con blobs y complica las revisiones. El zero-install cambia “esperar a instalar” por “cargar con el peso de las dependencias en tu control de versiones”, y no todos los equipos hacen ese trueque de buena gana.
| Eje | node_modules clásico | Plug’n’Play |
|---|---|---|
| Artefacto en disco | árbol de miles de archivos | un .pnp.cjs más zips |
| Resolución | Node camina por carpetas | mapa explícito parcheado |
| Arranque | stat de todo el árbol |
consulta al mapa, más rápido |
| Fantasmas | posibles en árbol plano | imposibles por el mapa |
| Compatibilidad | universal, todo la asume | requiere herramientas conscientes de PnP |
flowchart LR
imp[import express] --> q{como resuelve}
q -->|node_modules| walk[camina carpetas hacia arriba]
q -->|PnP| map[consulta el mapa pnp cjs]
walk --> disk[lee del arbol en disco]
map --> zip[abre el zip en yarn cache]
style q fill:#f9e2af,color:#11111b
style map fill:#89b4fa,color:#11111bPor qué no se impuso y el estado en 2026
El talón de Aquiles de PnP es la última fila de la tabla. Durante quince años, medio ecosistema asumió que node_modules existe como carpetas reales en disco: bundlers que leen archivos directamente, frameworks, editores, herramientas de compilación nativa, scripts que hacen stat de rutas. PnP rompe esa suposición universal.
Aunque Berry publicó un protocolo de parches y loaders conscientes de PnP, la fricción era constante: cada herramienta que no entendía el mapa había que adaptarla o remendarla. El propio yarn terminó añadiendo el linker de node-modules como vía de escape —una admisión implícita de que la compatibilidad pesaba más que la pureza—, y el coste de versionar zips incomodaba a equipos con repos ya grandes.
En 2026 el panorama está asentado. Yarn Berry, en su línea v4, sigue vivo y mantenido, con un ecosistema de plugins, un sistema de constraints para gobernar dependencias en monorepos, y uso a escala en algunas organizaciones —notablemente en el linaje de donde salió—. PnP conserva una minoría devota que valora sus garantías. Pero la corriente principal que quería estrictitud sin impuesto de compatibilidad eligió pnpm, que resuelve los mismos problemas —dedup y fantasmas— conservando un node_modules real que todas las herramientas ya sabían leer. Yarn Classic, por su parte, es fin de línea.
Classic (1.x)
Trajo lockfile, paralelismo y caché offline. Forzó a npm a mejorar y luego se congeló en mantenimiento. Hoy es legado.
Plug'n'Play
Sin node_modules: un mapa .pnp.cjs y zips. Resolución exacta, arranque rápido, fantasmas imposibles.
Zero-installs
Versiona la caché y el mapa: clonar es ejecutar. Potente para CI, pero hincha el repositorio de git.
La fricción
Rompe la suposición universal de node_modules. El impuesto de compatibilidad decidió la partida.
El desenlace de esta historia encierra una de las lecciones más contraintuitivas de la ingeniería de sistemas: pnpm no ganó por ser más radical que yarn PnP, sino por ser menos. Ambos diagnosticaron correctamente la misma enfermedad —duplicación y fantasmas nacidas del árbol plano— y ambos la curaron. La diferencia estuvo en el respeto a la interfaz existente. PnP declaró obsoleto el contrato que todo el ecosistema hablaba, node_modules como carpetas en disco, y pidió al mundo entero que se adaptara a un mecanismo mejor; pnpm mantuvo ese contrato intacto y arregló los problemas por debajo de él, con un node_modules que sigue siendo carpetas reales aunque ahora sean symlinks a un store. La corrección técnica de PnP era, discutiblemente, superior; la corrección compatible de pnpm fue la que triunfó, porque el coste de migración de una interfaz que usan decenas de miles de herramientas es un impuesto que la mayoría no está dispuesta a pagar por muy elegante que sea la alternativa. Esto es gravedad de ecosistema y dependencia de la trayectoria: el valor de un estándar no está solo en sus méritos intrínsecos, sino en la masa de cosas ya construidas sobre él, y romper esa masa tiene un precio que casi siempre se subestima. La enseñanza para tu carrera es doble y va más allá de los package managers. Primero, cuando diseñes algo que reemplace a un sistema establecido, pregúntate si puedes arreglar el problema conservando su interfaz en vez de sustituirla: casi siempre esa es la vía que la gente adopta. Segundo, no confundas superioridad técnica con éxito; el cementerio de las tecnologías está lleno de diseños mejores que perdieron ante diseños compatibles. PnP fue brillante y perdió, y entender por qué te hará tomar mejores decisiones que si solo miras cuál es “el más correcto”.
- En un proyecto de pruebas, activa Yarn Berry con PnP (
yarn set version stableynodeLinker: pnp) e inspecciona.pnp.cjs: localiza cómo un paquete concreto mapea a su zip y a sus dependencias permitidas. - Confirma la promesa de zero-install: clona o copia el repo con
.yarn/cachey.pnp.cjsversionados y ejecútalo sin correr una instalación. - Identifica una herramienta o script de tu flujo que asuma la existencia de
node_modulescomo carpetas y explica por qué PnP la rompería. - Cambia
nodeLinkeranode-modulesy razona qué garantías de PnP acabas de renunciar a cambio de compatibilidad. - Contrasta la estrategia de PnP (sustituir la interfaz) con la de pnpm (conservarla) y argumenta cuál habrías elegido para un equipo grande y por qué.