catalogMode: strict, prefer y manual
El ajuste catalogMode, disponible desde pnpm 10.12, gobierna cómo pnpm add interactua con el catalogo default: manual no lo toca, prefer lo usa con fallback, strict lo impone como unica fuente de versiones. Cuando usar cada uno y como convertir la coherencia en un guardarrail.
Definir un catálogo evita la deriva de las dependencias que ya están en él; pero ¿qué pasa cuando alguien ejecuta pnpm add lodash mañana? Sin una política, esa dependencia nueva entra directa al package.json y nace ya fuera del catálogo: la deriva vuelve por la puerta de atrás. catalogMode —el ajuste que pnpm estabilizó en la versión 10.12— cierra esa puerta al gobernar cómo pnpm add interactúa con el catálogo default. Sus tres valores, manual, prefer y strict, son en realidad tres niveles de compromiso con la fuente única de verdad, y elegir el correcto es una decisión de madurez del equipo, no solo de configuración.
- Entender qué controla exactamente
catalogMode: el comportamiento depnpm add. - Distinguir
manual,preferystrictpor lo que cada uno hace y prohíbe. - Elegir el modo según la etapa de adopción del catálogo en tu equipo.
- Conectarlo con
cleanupUnusedCatalogspara mantener el catálogo limpio.
Qué controla catalogMode
Conviene ser preciso sobre su alcance, porque es fácil sobreestimarlo. catalogMode no cambia cómo se resuelven los catalogs ni cómo se instalan las dependencias; controla solo si y cómo se añaden al catálogo default cuando ejecutas pnpm add. Es una política de escritura, no de lectura. No reescribe tus package.json existentes ni toca los catálogos nombrados: su radio de acción es el momento exacto en que introduces una dependencia nueva desde la línea de comandos. Se declara en pnpm-workspace.yaml y su valor por defecto es manual.
catalogMode: strict
catalog:
react: ^18.3.1
lodash: ^4.17.21
A partir de ahí, cada pnpm add consulta esta política antes de decidir dónde escribe la versión de la dependencia nueva: directamente en el package.json, referenciándola en el catálogo, o rechazándola si viola la regla.
flowchart TD Q[pnpm add una dependencia] --> M[modo del catalogo] M -->|manual| D1[version directa al package.json] M -->|prefer| D2[del catalogo si compatible, si no directa] M -->|strict| D3[solo del catalogo o error] style D1 fill:#f9e2af,color:#11111b style D2 fill:#89b4fa,color:#11111b style D3 fill:#a6e3a1,color:#11111b
Los tres modos, de menos a más compromiso
Los tres valores forman una escala de compromiso creciente con el catálogo; conviene recorrerlos en orden, porque cada uno asume lo que el anterior dejaba a la disciplina humana.
manual: el punto de partida
manual es el valor por defecto y el comportamiento clásico: pnpm add no toca el catálogo en absoluto. La versión de la dependencia nueva aterriza directamente en el package.json, como siempre. El catálogo existe, pero mantenerlo es una tarea enteramente humana: eres tú quien decide qué entra y quién edita pnpm-workspace.yaml.
# con catalogMode manual
pnpm add lodash
# resultado en package.json: "lodash": "^4.17.21"
# el catalogo no se toca; si querias centralizarlo, lo haces a mano
Es el modo correcto para empezar, cuando el catálogo aún es pequeño y solo cubre un puñado de dependencias críticas, o cuando prefieres control total y curación manual sobre qué se centraliza. Su debilidad es evidente y es la razón de existir de los otros dos modos: no impide que nazcan dependencias fuera del catálogo, así que la coherencia depende por completo de la disciplina de quien teclea el comando.
Un matiz importante: manual no es “sin catalogs”. Los catalogs que ya definiste siguen funcionando con normalidad —se resuelven, se referencian con catalog:, se reescriben al publicar— exactamente igual que en los otros modos. Lo único que manual no hace es mover automáticamente al catálogo lo que añades con pnpm add. Es la diferencia entre “tengo un catálogo y lo mantengo a mano” y “tengo un catálogo y la herramienta me ayuda a alimentarlo”: ambos son catalogs plenamente operativos.
prefer: adopción sin fricción
prefer inclina la balanza hacia el catálogo sin volverlo obligatorio. Cuando añades una dependencia que ya está en el catálogo y el rango es compatible, pnpm add la referencia con catalog: en lugar de escribir el número. Si no hay una versión compatible en el catálogo, hace fallback a una dependencia directa, sin error.
# con catalogMode prefer, react ya esta en el catalogo
pnpm add react
# resultado en package.json: "react": "catalog:" (usa el catalogo)
pnpm add chalk
# chalk no esta en el catalogo -> fallback a directa: "chalk": "^5.3.0"
Es el modo de la transición, y probablemente donde más equipos deberían vivir la mayor parte del tiempo. Premia el uso del catálogo —lo correcto se vuelve también lo automático— sin bloquear a nadie que necesite algo que aún no está catalogado. Un equipo que está migrando, o que quiere fomentar la centralización sin convertirla en un obstáculo para el trabajo diario, encuentra en prefer el equilibrio: empuja hacia la coherencia con un codo suave en vez de con un muro.
strict: la política que impide la deriva
strict es el compromiso total: solo permite versiones que estén en el catálogo. Añadir una dependencia cuya versión cae fuera del rango del catálogo provoca un error en lugar de escribir una versión divergente. La deriva no se detecta después: se vuelve imposible en el momento de intentar introducirla.
# con catalogMode strict
pnpm add react # esta en el catalogo y compatible -> ok, usa catalog:
pnpm add react@19 # fuera del rango del catalogo -> ERROR, no lo escribe
Es el modo de un monorepo maduro que ya consolidó sus versiones y quiere que el propio tooling defienda esa consolidación. Convierte la coherencia de una convención que hay que vigilar en un invariante que la herramienta hace cumplir: nadie puede, ni queriendo por descuido, introducir una segunda versión de una dependencia catalogada. El coste es una fricción deliberada —a veces querrás una versión nueva y el comando te frenará— pero esa fricción es precisamente el punto: te obliga a tomar la decisión en el sitio correcto, el catálogo, y no de tapadillo en un package.json cualquiera.
| Modo | pnpm add de algo catalogado |
pnpm add de algo nuevo o incompatible |
|---|---|---|
manual |
versión directa al package.json |
versión directa; no toca el catálogo |
prefer |
lo referencia con catalog: |
fallback a versión directa |
strict |
lo referencia con catalog: |
error: lo rechaza |
El ajuste hermano cleanupUnusedCatalogs (disponible desde pnpm 10.15) ataca el problema opuesto: entradas del catálogo que ya no usa ningún paquete. Con el valor por defecto false, esas entradas huérfanas se acumulan; puestas a true, pnpm las elimina durante la instalación. Un catálogo con strict para que nada entre fuera de él y cleanupUnusedCatalogs para que nada sobre dentro de él se mantiene ajustado a la realidad del repo sin curación manual, cerrando el ciclo por sus dos extremos.
Los cuatro comportamientos que rodean al catálogo caben en un vistazo, y conviene tenerlos juntos antes de cablear la configuración de tu repo:
manual (default)
pnpm add no toca el catálogo; la versión va directa al package.json. Control total, coherencia por disciplina.
prefer
Usa catalog: si la dependencia está catalogada y es compatible; si no, cae a versión directa sin error.
strict
Solo versiones del catálogo. Añadir algo fuera de rango falla: la deriva se vuelve imposible, no solo detectable.
cleanupUnusedCatalogs
Complemento: elimina en la instalación las entradas del catálogo que ya no usa ningún paquete.
Un monorepo maduro combina las dos políticas para blindar el catálogo por sus dos extremos —lo que entra y lo que sobra— en apenas dos líneas de configuración:
catalogMode: strict # nada entra fuera del catalogo
cleanupUnusedCatalogs: true # nada sobra dentro del catalogo
catalog:
react: ^18.3.1
react-dom: ^18.3.1
typescript: ^5.4.5
Elegir el modo: una curva de madurez
Los tres modos no son alternativas de gusto, sino etapas de un mismo camino. Un repo joven empieza en manual, catalogando a mano solo lo crítico mientras el equipo aprende el patrón. Cuando el catálogo cubre lo esencial y quieres fomentar su uso sin frenar a nadie, subes a prefer, que hace del catálogo el camino de menor resistencia. Y cuando la consolidación está hecha y quieres blindarla, pasas a strict, que impide que se rompa. Cada escalón aprieta un poco más la garantía a cambio de un poco menos de libertad, y el orden natural es de menos a más a medida que el equipo confía en su catálogo.
El error a evitar es saltar directo a strict en un repo que aún no ha consolidado: si el catálogo está incompleto, strict convierte cada pnpm add legítimo en una pelea, y el equipo aprende a odiar el sistema en vez de a apoyarse en él. La regla sana es que el modo siga a la madurez del catálogo, no que la fuerce: endurece la política cuando el catálogo ya merezca ser obligatorio, no antes.
Y aunque catalogMode gobierna el catálogo default, la disciplina que impone se combina de forma natural con los catálogos nombrados de la migración gradual: strict garantiza que nadie introduzca una tercera versión por descuido, mientras los nombrados sostienen, a propósito, las dos versiones que sí decidiste mantener. La política automatizada y las excepciones deliberadas no se estorban; se refuerzan, porque cada una cubre lo que la otra no puede.
Como catalogMode se declara en pnpm-workspace.yaml, versionado en git, la regla es la misma para todo el equipo y para el CI: no depende de la configuración local de cada quien. Quien clona el repo hereda la política sin instalar ni configurar nada. Esa es la diferencia entre una regla que aplica de verdad y una que solo aplica en las máquinas que se acordaron de activarla.
La historia de la ingeniería de software a escala es, en buena parte, la historia de convertir convenciones que dependen de la disciplina humana en garantías que hace cumplir una máquina. “Formatea así” se volvió un formatter; “no rompas los tipos” se volvió un type checker; “no dejes deuda de estilo” se volvió un linter en CI. catalogMode: strict es exactamente ese movimiento aplicado a las versiones de dependencias: coge la regla “en este repo hay una sola versión de cada dependencia compartida” —que antes era un acuerdo que alguien tenía que recordar y vigilar en cada revisión— y la convierte en algo que el package manager sencillamente no te deja violar. La diferencia entre ambos mundos es enorme. Una convención social falla en silencio: basta un despiste, un colaborador nuevo que no la conoce, una prisa un viernes, para que la deriva vuelva. Una garantía mecánica falla en ruidoso y temprano: el error salta en el pnpm add, antes del commit, cuando corregirlo cuesta un segundo. Por eso la progresión manual a prefer a strict no es solo técnica: es la trayectoria de un equipo que va trasladando el peso de la coherencia desde la memoria de las personas hacia las barandillas del sistema. El objetivo último no es tener un catálogo, sino llegar a un estado en el que la deriva ya no sea algo que se pueda cometer. strict es el nombre de ese estado, y prefer es la rampa honesta que te lleva hasta él sin castigar al equipo por el camino.
- Averigua en qué modo está hoy tu repo (o asume
manual, el default) y decide cuál sería el correcto para su etapa actual. - Con
catalogMode: prefer, ejecutapnpm addde algo ya catalogado y de algo nuevo; observa que uno usacatalog:y el otro cae a versión directa. - Cambia a
stricte intentapnpm addde una versión fuera del rango del catálogo; confirma que la herramienta lo rechaza. - Activa
cleanupUnusedCatalogsy comprueba qué entradas huérfanas desaparecen en la siguiente instalación. - Escribe la regla en una frase para tu equipo: en qué modo estáis, por qué, y qué haría falta para subir al siguiente escalón.