Monorepo vs polyrepo: los trade-offs
Los trade-offs reales entre un repositorio único y muchos repos: acoplamiento frente a fronteras físicas, permisos por repo frente a CODEOWNERS por ruta, autonomía de equipo frente a consistencia, y dónde se paga la integración. Por qué la elección es integrar ahora o integrar después.
La alternativa al monorepo no es “no tener estructura”, es el polyrepo: cada proyecto y cada librería en su propio repositorio, versionados y publicados de forma independiente, consumidos a través del registro. La discusión “monorepo o polyrepo” suele degenerar en religión, pero debajo hay trade-offs concretos y medibles: acoplamiento, permisos, autonomía de equipo, tooling. Verlos sin bando revela que no eliges entre una carpeta o muchas, sino entre cuándo pagas el coste de que tus piezas encajen.
- Definir el polyrepo y su modelo de integración vía registro y versiones.
- Sopesar los trade-offs reales: acoplamiento, permisos, velocidad y tooling, sin dogma.
- Entender dónde se rompe cada modelo a escala y qué inversión exige.
- Reencuadrar la decisión como integrar ahora frente a integrar después.
Dos formas de repartir el código
En el polyrepo, cada unidad —una app, una librería— vive en su propio repositorio con su historia de git, su CI, sus permisos y su ciclo de publicación. Compartir código significa publicar un paquete en un registro y consumirlo con una versión semántica, exactamente como consumes cualquier dependencia de terceros. La frontera entre proyectos es física: no puedes importar lo que otro equipo no ha publicado, y punto.
En el monorepo, como vimos, todo comparte un grafo, un lockfile y una cadena de herramientas, y las piezas se referencian con workspace: sin pasar por el registro. La frontera entre proyectos es lógica: existe por convención y por tooling, no porque el sistema de archivos lo impida. Esa diferencia —frontera física frente a frontera lógica— es la raíz de casi todos los trade-offs que siguen, porque decide si la separación te la garantiza el sistema o te la tienes que ganar con disciplina.
# polyrepo: compartir codigo es publicar y versionar
npm publish @acme/utils # y esperar, e instalar, y fijar version
# monorepo: compartir codigo es una linea en package.json
# "@acme/utils": "workspace:*"
Conviene desactivar de entrada un falso amigo: “monorepo” no implica “un solo despliegue” ni “todo el mundo lo ve todo”, igual que “polyrepo” no implica “microservicios”. Son decisiones ortogonales que la gente suele agrupar por costumbre. Aquí comparamos solo la topología del código fuente; cómo despliegas y cómo aíslas el runtime es harina de otro costal.
Que la topología del repo sea ortogonal al despliegue no significa que dé igual: condiciona qué es fácil. Un monorepo no te obliga a un monolito, pero hace trivial compartir código entre servicios; un polyrepo no te obliga a microservicios, pero hace natural que cada servicio evolucione solo. La topología no decide tu arquitectura de runtime, pero inclina la mesa hacia ciertas formas, y con el tiempo las mesas inclinadas deciden.
Los trade-offs reales
Acoplamiento
Monorepo: cambio atómico fácil, pero también acoplamiento accidental fácil; las fronteras las impone el tooling. Polyrepo: el registro impide importar lo no publicado, a costa de fricción.
Permisos
Polyrepo: ACL por repo, trivial abrir una lib y cerrar un servicio. Monorepo: todo o casi todo visible; necesitas CODEOWNERS por ruta y, a gran escala, checkout disperso.
Velocidad de equipo
Monorepo: un cambio cruza fronteras en un commit; consistencia por defecto. Polyrepo: cada equipo su cadencia y su tooling, autonomía a cambio de deriva.
Tooling
Monorepo: una cadena de herramientas para todos, coherencia difícil de romper. Polyrepo: libertad para divergir, cada repo reinventa su CI.
El acoplamiento es el trade-off más malinterpretado. Se dice que el monorepo “acopla”; en rigor, el monorepo facilita tanto el desacoplamiento sano —código compartido limpio— como el acoplamiento insano —que todo importe de todo porque puede—. El polyrepo impone desacoplamiento por la fuerza bruta de la frontera física: si no está publicado, no lo importas. Eso previene el barro, pero también convierte cada extracción de código compartido en un proyecto de publicación. Son dos formas de pagar: el monorepo con disciplina de tooling, el polyrepo con fricción de publicación.
Un ejemplo lo hace visible. En un polyrepo, si @acme/utils no está publicado, importarlo simplemente no compila: la frontera es un muro que el sistema levanta por ti. En un monorepo, ese mismo import funciona porque el paquete ya está en el grafo, y nada te impide crear una dependencia que quizá no querías. El muro que el polyrepo pone por defecto, el monorepo te pide construirlo tú con reglas de frontera y revisión.
Los permisos son la ventaja más honesta del polyrepo. Dar a un contratista acceso a una sola librería, o abrir en código abierto un paquete mientras el resto sigue privado, es trivial cuando cada cosa es un repo con su propia ACL. En un monorepo todo el árbol tiende a ser visible para quien tiene acceso, y restringir por carpeta exige CODEOWNERS para revisión y, a escala Google o Meta, checkout disperso o clonado parcial con infraestructura a medida.
# CODEOWNERS: revision por ruta, el sucedaneo monorepo del permiso por repo
/packages/ui/ @equipo-design-system
/apps/pagos/ @equipo-pagos @seguridad
/tooling/ @plataforma
Fíjate en el matiz: CODEOWNERS gobierna quién revisa, no quién puede leer. Si tu organización necesita aislamiento de lectura por proyecto —contratistas, cumplimiento normativo—, el polyrepo te lo regala y el monorepo te lo cobra en infraestructura. Es la dimensión donde el polyrepo gana sin matices, y conviene reconocerlo en lugar de racionalizarlo.
La velocidad de equipo corta en ambos sentidos, y ahí está su sutileza. El monorepo acelera el cambio transversal —tocar varias piezas a la vez— y regala consistencia: todos comparten versiones, tooling y convenciones sin esfuerzo. El polyrepo acelera el cambio local y la autonomía: cada equipo elige su stack, su cadencia de release y su CI sin pedir permiso ni esperar a un pipeline compartido. A pequeña y mediana escala el cambio transversal es frecuente y el monorepo gana; a gran escala, con equipos que rara vez se pisan, la autonomía del polyrepo puede pesar más que la coherencia.
El tooling es la cara técnica de ese mismo eje. El monorepo empuja hacia una sola cadena de herramientas —un tsconfig, un linter, un formateador— que es una bendición para la coherencia y una fricción cuando un equipo quiere experimentar con algo distinto. El polyrepo deja divergir: libertad para probar, a cambio de que cada repo reinvente su CI y de que las buenas prácticas no se propaguen solas. Estandarización frente a experimentación, otra vez el mismo trade-off con otro nombre.
Fíjate en el patrón: acoplamiento, permisos, velocidad, tooling… todos son variaciones de una sola tensión, la que hay entre integrar y unificar frente a aislar y diversificar. El monorepo tira siempre hacia lo primero; el polyrepo hacia lo segundo. Por eso no hay que memorizar cuatro trade-offs independientes: basta con entender ese eje y saber que cada dimensión concreta es una proyección suya sobre un aspecto distinto del trabajo.
Escala: dónde se rompe cada modelo
Ninguno de los dos escala gratis; se rompen por sitios opuestos. El monorepo tensa las herramientas: git empieza a sufrir con árboles enormes —de ahí Sapling y EdenFS en Meta, Piper en Google—, el servidor de TypeScript se ralentiza sobre un grafo gigante, y el CI ingenuo castiga a todos con el coste del repo entero. Superar eso exige la inversión que vimos en la lección anterior: caché de tareas, ejecución por afectados, quizás VCS a medida. La mayoría de equipos nunca llega a ese punto, pero conviene saber que existe y que tiene un precio en infraestructura y personas.
El polyrepo tensa la integración. Con cincuenta repos hay cincuenta lockfiles, cincuenta pipelines y, sobre todo, deriva de versiones entre repos: la integración solo ocurre al publicar y consumir, así que las incompatibilidades se descubren tarde y lejos de donde nacieron.
# deriva entre repos: nadie la ve hasta que coinciden en un tercero
repo-checkout usa @acme/utils 2.1.0
repo-pagos usa @acme/utils 1.8.0 <- se quedo atras
repo-dashboard importa de ambos <- aqui estalla, en runtime
El monorepo no puede tener esa forma de deriva para el código interno: hay un solo grafo y una sola versión resuelta. No hace desaparecer el problema, lo cambia de sitio —de la integración diferida a la escala del tooling—. Cada topología tiene su clase de dolor característica, y madurar es saber cuál prefieres administrar.
Dicho de otro modo: el polyrepo empuja la complejidad hacia fuera de cada repo —a la red de versiones que los conecta— y el monorepo la concentra dentro —en el tooling que mantiene manejable un árbol enorme—. Elegir topología es decidir dónde quieres que viva tu complejidad, no si quieres tenerla.
La elección no es binaria. Muchas organizaciones maduras corren un puñado de monorepos por dominio —producto, plataforma, infraestructura— en lugar de un único repo planetario o mil repos atomizados. Es un “polyrepo de monorepos”: dentro de cada dominio disfrutas del cambio atómico y la coherencia; entre dominios aceptas fronteras físicas y versionado por registro, que ahí sí quieres. El tamaño óptimo del monorepo es una decisión de dominio, no un absoluto.
Dónde se paga la integración
Reunidos los trade-offs, todos apuntan a una misma variable oculta: el momento de la integración. El monorepo integra en el instante presente —cada commit se valida contra el HEAD de todo lo demás— y por eso el cambio atómico es barato y la coherencia es el estado por defecto; el precio es que las fronteras hay que imponerlas con tooling y que las herramientas sufren a escala. El polyrepo difiere la integración al momento de publicar y consumir, y por eso da autonomía, permisos limpios y cadencias independientes; el precio es la deriva de versiones y las sorpresas de compatibilidad que llegan tarde.
flowchart TD M[monorepo integra en cada commit contra HEAD] --> MC[cambio atomico barato coherencia por defecto] M --> MP[precio fronteras por tooling y VCS a escala] P[polyrepo integra al publicar y consumir] --> PC[autonomia permisos y cadencias propias] P --> PP[precio deriva de versiones y sorpresas tardias] style MC fill:#a6e3a1,color:#11111b style PC fill:#a6e3a1,color:#11111b style MP fill:#f9e2af,color:#11111b style PP fill:#f9e2af,color:#11111b
Puesto en una tabla, el eje temporal ordena de golpe todo lo anterior:
monorepo polyrepo
integracion en cada commit al publicar y consumir
coherencia por defecto hay que construirla
cambio transversal un commit N pull requests
aislamiento acceso CODEOWNERS y mas ACL por repo, trivial
limite de escala tooling y VCS deriva de versiones
Por eso la pregunta útil no es “¿monorepo o polyrepo?”, sino “¿mi organización se beneficia más de integrar continuamente o de aislar y diferir?”. Un equipo de producto que refactoriza a través de fronteras a diario quiere integrar ahora: monorepo. Una plataforma con muchos consumidores externos y equipos que deben avanzar a ritmos distintos quiere aislar: polyrepo, o monorepos por dominio. La respuesta correcta depende de qué coste te duele menos pagar, y ese es un juicio de contexto, no una verdad universal.
Fíjate en que ninguno de los factores decisivos es puramente técnico: ritmo de cambio, autonomía de los equipos, necesidades de permisos, capacidad de invertir en tooling. La topología del repositorio la determina, en el fondo, la forma de tu organización más que la de tu código. Por eso dos empresas con stacks idénticos pueden acertar con decisiones opuestas: no están respondiendo a la misma pregunta, aunque usen las mismas palabras.
Adoptar un monorepo porque “lo usa una big tech” es copiar la respuesta sin leer la pregunta. Google y Meta viven en monorepo y han invertido años en VCS, build systems y tooling a medida para sostenerlo. Sin esa inversión, un monorepo mal soportado reproduce los peores rasgos de ambos mundos: el CI lento del monorepo sin su cambio atómico fluido, o la deriva del polyrepo sin su autonomía. Elige por tu ritmo de cambio real y tu capacidad de invertir en tooling, no por prestigio ajeno.
El debate monorepo contra polyrepo se libra casi siempre con los argumentos equivocados —“un repo es más ordenado”, “muchos repos dan libertad”— porque discute la forma cuando lo que está en juego es el tiempo. Todo sistema compuesto de partes tiene que integrarlas en algún momento: comprobar que la versión de una encaja con la de otra, que un cambio en una no rompe a la que la usa. La única decisión de fondo es cuándo pagas esa comprobación. El monorepo la paga ahora, en cada commit, contra el estado actual de todo lo demás; por eso la coherencia es su estado natural y el cambio atómico su superpoder, y por eso su factura llega en forma de tooling —fronteras que imponer, cachés que construir, un VCS que a escala hay que reforzar—. El polyrepo la paga después, al publicar y consumir; por eso reparte autonomía, permisos limpios y ritmos propios, y por eso su factura llega en forma de deriva de versiones y de incompatibilidades que se descubren lejos de donde nacieron. No hay una opción sin coste: hay una que integra pronto y barato pero exige disciplina, y otra que aplaza el coste a cambio de deuda que se acumula. Interiorizar esto disuelve la guerra santa. Dejas de preguntar cuál es “mejor” y empiezas a preguntar cuál es el ritmo de cambio de tu organización, cuánta autonomía necesitan sus equipos, cuánto aislamiento de permisos exige su negocio y cuánta infraestructura puede permitirse. La respuesta —un monorepo, varios monorepos por dominio, un polyrepo— cae sola en cuanto sabes cuándo prefieres pagar la integración. La topología del repositorio no es una preferencia estética: es una decisión sobre la economía temporal de que tus piezas encajen.
- Cuenta cuántos repos tiene hoy tu equipo y cómo comparten código entre ellos: ¿por registro, por copia, por submódulos de git?
- Recuerda la última incompatibilidad de versiones entre dos repos vuestros. ¿Cuánto tardó en descubrirse desde que se introdujo? Esa distancia es tu deuda de integración diferida.
- Enumera qué proyectos necesitan permisos aislados de verdad —contratistas, código abierto parcial—. Si son muchos, el polyrepo te está dando algo real.
- Estima el ritmo de cambios que cruzan fronteras de proyecto por semana. Si es alto, el cambio atómico del monorepo te ahorraría mucha coordinación.
- Decide, con una frase justificada: ¿tu organización prefiere integrar ahora o después? Escribe la topología que se sigue de esa respuesta.