Monorepo vs polyrepo: mantener sincronizados web, móvil y backend
Monorepo vs polyrepo explicado para equipos que publican apps web, móviles y backend. Compara dependencias, coordinación de releases y tácticas de CI para mantener la velocidad.

El problema real: entregar cambios en tres bases de código
Los equipos no discuten monorepo vs polyrepo por filosofía de Git. Discuten porque un pequeño cambio de producto se convierte en tres cambios separados para web, móvil y backend, y algo se rompe en el camino.
Lo que suele romperse primero rara vez es la UI. Normalmente es el pegamento invisible: un contrato de API que cambió sin una actualización correspondiente, una librería compartida que se actualizó en un lugar pero no en otro, o la canalización de build que de repente necesita un paso nuevo. Cuando una pieza se despliega antes que las otras, los usuarios lo sienten como bugs tipo “el botón existe en web pero la app móvil dice no compatible” o “la app carga indefinidamente porque la respuesta del backend cambió”.
Web, móvil y backend también funcionan con relojes de despliegue distintos. Web puede publicar muchas veces al día. Backend puede publicar a menudo, pero necesita un despliegue cuidadoso. Móvil es el más lento por la revisión en las tiendas y la actualización de usuarios. Un cambio “simple” como renombrar un campo puede obligarte a planear alrededor del carril más lento, aunque solo una pantalla lo necesite.
Probablemente estás pagando un impuesto de coordinación de repos si esto sigue ocurriendo:
- Cambios de API que rompen se descubren después del merge.
- Alineación de versiones depende de recordatorios manuales y hojas de cálculo.
- Una función necesita múltiples pull requests coordinados que quedan esperando unos a otros.
- CI es lento porque construye y prueba mucho más de lo que tocó el cambio.
- Los rollbacks dan miedo porque no está claro qué commit coincide con qué release.
El tamaño del equipo y la madurez del producto cambian la respuesta correcta. Al principio, la mayoría gana haciendo la coordinación barata y la visibilidad alta, aunque sea un poco desordenado. A medida que los equipos crecen, las fronteras empiezan a importar, pero solo si las interfaces son estables y la propiedad está clara.
Si cada cambio importante debe aterrizar en tres sitios, pagarás ese impuesto de alguna forma. La estrategia de repos trata principalmente de cómo quieres pagarlo.
Monorepo y polyrepo sin jerga
Un repositorio es simplemente donde vive tu código, junto con su historial. Cuando tienes web, móvil y backend, la elección es sencilla: mantener todo junto o dividirlo.
Un monorepo es un repositorio que contiene múltiples apps y a menudo código compartido también. Web, iOS/Android, servicios backend y librerías compartidas conviven lado a lado.
Un polyrepo es lo contrario: cada app (y a veces cada servicio) tiene su propio repositorio. El código compartido suele convertirse en un paquete separado o los equipos copian piezas pequeñas cuando las necesitan.
En el día a día, los monorepos suelen sentirse así: compartir código es fácil, los cambios cross-app pueden estar en un solo pull request y las reglas son consistentes. El intercambio social es que la propiedad puede volverse difusa a menos que fijes límites claros, y las comprobaciones a nivel de repo pueden sentirse estrictas.
Los polyrepos suelen sentirse así: cada equipo puede moverse independientemente, los repos se mantienen enfocados y el control de acceso suele ser más simple. El intercambio es la coordinación: compartir código exige planificación y los cambios cross-app suelen convertirse en varios pull requests con timing cuidado.
Muchos equipos acaban con un híbrido: apps en repos separados, contratos compartidos en un sitio; o un monorepo con límites fuertes para que cada equipo se quede mayormente en su área.
Si usas una plataforma que genera backend, web y móvil desde una sola fuente de verdad, reduces la deriva porque contratos y lógica conviven. AppMaster, por ejemplo, genera backend listo para producción, web y apps nativas desde un único modelo. Eso no elimina las realidades de lanzamiento (móvil sigue enviando más lento), pero puede quitar gran parte del “¿actualizamos los tres?”.
Gestión de dependencias: mantener el código compartido a salvo
El código compartido es donde los equipos pierden tiempo, sea cual sea la disposición de repos. Un pequeño cambio en una librería compartida o en un contrato API puede romper builds web, lanzamientos móviles y despliegues backend de maneras distintas.
Cuando compartes librerías (componentes UI, reglas de validación, helpers de auth), eliges entre una versión para todos o múltiples versiones en el tiempo.
- Una versión es más simple y evita sorpresas de “funciona en mi rama”.
- Múltiples versiones dejan a los equipos avanzar a su ritmo, pero crean desorden y dificultan aplicar correcciones de seguridad.
Los clientes de API y esquemas merecen cuidado extra. Las actualizaciones manuales son lentas y propensas a errores. Un mejor patrón es tratar el esquema de la API como fuente de la verdad y generar clientes desde él, luego registrarlos o generarlos en CI. La meta es fallar rápido: si el backend añade un campo obligatorio, el cliente móvil debería romperse en build, no tres días después en QA.
Los cambios que rompen se extienden cuando el comportamiento cambia sin una ruta segura hacia adelante. Prefiere cambios aditivos primero (campos nuevos, endpoints nuevos) y depreca después. Si debes romper algo, usa endpoints versionados o una ventana de compatibilidad corta.
Ejemplo concreto: el backend renombra status a state. Si web se actualiza hoy pero móvil no puede publicar hasta dentro de una semana, el backend debe aceptar ambos campos durante esa semana o publicar un adaptador que mapee el campo antiguo al nuevo.
Algunas reglas que mantienen las actualizaciones de dependencias aburridas (en el buen sentido):
- Actualiza con cadencia. Actualizaciones pequeñas semanales vencen a grandes trimestrales.
- Requiere aprobación explícita para cambios que rompen, más una nota corta de migración.
- Automatiza comprobaciones: actualizaciones de dependencias, regeneración de clientes y tests básicos de contrato.
- Define “hecho” como “web, móvil y backend pasan el build”, no “mi repo pasa”.
El código generado puede reducir la deriva, pero no sustituye la disciplina. Todavía necesitas un contrato, deprecaciones claras y actualizaciones predecibles.
Coordinación de releases: alinear web, móvil y backend
La coordinación de releases es donde la estrategia de repos deja de ser teórica. Si el backend cambia el nombre de un campo de la API, la app web suele actualizar y publicar el mismo día. Las apps móviles son distintas: la revisión en la tienda y el tiempo que tardan los usuarios en actualizar pueden convertir un pequeño desajuste en una semana de tickets de soporte.
La meta práctica es simple: una acción del usuario debe funcionar sin importar qué parte se actualice primero. Eso significa planear para versiones mixtas, no asumir un despliegue perfectamente sincronizado.
Patrones de versionado que usan los equipos
La mayoría de equipos se asienta en uno de estos enfoques:
-
Un tren de releases compartido: web, móvil y backend se publican como una unidad versionada.
-
Versiones por servicio con reglas de compatibilidad: cada app/servicio tiene su propia versión y el backend soporta un rango definido de versiones cliente.
Un tren de release compartido parece ordenado, pero suele romperse con los retrasos móviles. Las versiones por servicio son más desordenadas en el papel, pero reflejan la realidad. Si vas por servicio, escribe una regla y aplícala: qué versiones de backend deben soportar qué versiones móviles y durante cuánto.
Los retrasos móviles también cambian cómo manejas hotfixes. Los hotfixes en backend pueden salir rápido; los móviles pueden tardar días en llegar a usuarios. Prefiere arreglos server-side que mantengan viejas builds móviles funcionando. Cuando debas cambiar el cliente, usa feature flags y evita quitar campos antiguos hasta saber que la mayoría de usuarios se ha actualizado.
Ejemplo: añades “instrucciones de entrega” al flujo de pedido. El backend añade un campo opcional nuevo, web lo muestra de inmediato y móvil lo muestra en el siguiente sprint. Si el backend acepta peticiones antiguas y mantiene el campo opcional, todo sigue funcionando mientras móvil se pone al día.
¿Quién posee el calendario de releases?
La coordinación falla cuando “todo el mundo lo posee” y, por tanto, nadie lo hace. El propietario puede ser un tech lead, un release manager o un product manager con fuerte apoyo de ingeniería. Su trabajo es prevenir sorpresas manteniendo expectativas de release visibles y consistentes.
No necesitan un proceso complejo. Necesitan hábitos repetibles: un calendario de releases simple con cortes y ventanas de freeze, una revisión rápida entre equipos antes de que un cambio de API se publique, y un plan claro para qué hacer si móvil se retrasa (retenemos el backend vs mantenemos compatibilidad).
Si tu flujo genera web, móvil y backend juntos desde un modelo, aún necesitas un dueño de releases. Normalmente habrá menos momentos de “¿actualizamos los tres lugares?”, pero no escaparás del timing móvil.
Mantener el tiempo de CI bajo control
CI se vuelve lento por las mismas razones en ambos montajes: reconstruyes demasiado, vuelves a instalar dependencias repetidamente y ejecutas todas las pruebas en cada cambio.
Los ladrones de tiempo comunes incluyen builds completos por pequeños cambios, caches inexistentes, suites de tests que ejecutan todo y jobs seriales que podrían ejecutarse en paralelo.
Empieza con mejoras que ayudan en todas partes:
- Cachea descargas de dependencias y resultados de build.
- Ejecuta lint, unit tests y builds en paralelo cuando sea posible.
- Separa comprobaciones rápidas (cada commit) de comprobaciones lentas (rama principal, nocturnas o pre-release).
Tácticas de monorepo que ayudan
Los monorepos se vuelven dolorosos cuando cada commit dispara una pipeline de “construir el mundo”. La solución es construir y probar solo lo afectado por el cambio.
Usa filtros por ruta y un enfoque solo-para-lo-afectado: si cambias código UI móvil, no reconstruyas imágenes backend. Si tocaste una librería compartida, construye y prueba solo las apps que dependen de ella. Muchos equipos formalizan esto con un grafo de dependencias simple para que CI decida en vez de adivinar.
Tácticas de polyrepo que previenen la deriva
Los polyrepos pueden ser rápidos porque cada repo es más pequeño, pero suelen perder tiempo por duplicación e inconsistencia en herramientas.
Mantén un conjunto compartido de plantillas de CI (mismos pasos, mismos caches, mismas convenciones) para que cada repo no reinventen la pipeline. Fija toolchains (versiones de runtimes, herramientas de build, linters) para evitar sorpresas de “funciona en un repo”. Si las descargas de dependencias son un cuello de botella, configura caches compartidos o mirrors internos para que cada repo no baje todo desde cero.
Ejemplo concreto: una función añade un nuevo campo “status”. Backend cambia, web lo muestra, móvil lo muestra. En un monorepo, CI debería ejecutar tests backend más solo las partes de web y móvil que dependen del cliente API. En un polyrepo, cada repo debe ejecutar sus checks rápidos, y una pipeline de integración separada puede validar que las tres releases aún coinciden.
Si exportas código fuente y ejecutas tu propio CI, la misma regla aplica: construye solo lo que cambió, reutiliza caches agresivamente y reserva comprobaciones lentas para cuando aporten valor real.
Paso a paso: elige una estrategia de repos que encaje con tu equipo
La decisión se vuelve más fácil cuando partes de tu trabajo diario en vez de ideología.
1) Anota qué debe cambiar junto
Elige 5 a 10 funciones recientes y apunta qué tuvo que moverse al mismo tiempo. Marca si cada una tocó pantallas UI, endpoints API, tablas de datos, reglas de autenticación o validación compartida. Si la mayoría de funciones requieren cambios coordinados en las tres áreas, una separación estricta resultará dolorosa a menos que tu proceso de releases sea muy disciplinado.
2) Rastrear código y decisiones compartidas
El código compartido no son solo librerías. También son contratos (esquemas API), patrones UI y reglas de negocio. Anota dónde viven hoy, quién los edita y cómo se aprueban los cambios. Si las piezas compartidas se copian entre repos, eso indica que necesitas mayor control, ya sea con un monorepo o reglas estrictas de versionado.
3) Define límites y propietarios
Decide cuáles son las unidades (apps, servicios, librerías) y asigna un propietario a cada unidad. Los límites importan más que la disposición del repo. Sin propietarios, un monorepo se vuelve ruidoso. Sin propietarios, un polyrepo se desconecta.
Si quieres una lista simple: un repo o carpeta por servicio/app desplegable, un sitio para contratos compartidos, un sitio para componentes UI verdaderamente compartidos, una regla clara de dónde vive la lógica de negocio y un propietario documentado para cada uno.
4) Elige un modelo de releases que puedas seguir
Si los lanzamientos móviles se retrasan respecto al backend, necesitas un plan de compatibilidad (APIs versionadas, campos retrocompatibles o una ventana de soporte definida). Si todo debe publicarse junto, un tren de releases puede funcionar, pero aumenta la coordinación.
Mantén reglas de branching aburridas: ramas de corta vida, merges pequeños y un camino claro para hotfixes.
5) Diseña CI alrededor de cambios comunes
No diseñes CI para el peor caso desde el día uno. Diseñala para lo que la gente hace a diario.
Si la mayoría de commits tocan solo UI web, ejecuta lint y unit tests web por defecto y ejecuta pruebas end-to-end completas en schedule o antes de releases. Si los incidentes vienen de deriva de API, invierte primero en tests de contrato y generación de clientes.
Ejemplo: una función que toca web, móvil y backend
Imagina un equipo pequeño construyendo tres cosas a la vez: un portal cliente (web), una app de campo (móvil) y una API (backend). Llega una petición: añadir un nuevo campo “Service status” a los trabajos y mostrarlo en todas partes.
El cambio parece pequeño, pero es una prueba de coordinación. Backend añade el campo y actualiza validaciones y respuestas. Web lo muestra y actualiza filtros. Móvil necesita mostrarlo offline, sincronizarlo y manejar casos borde.
Ahora el problema real: el cambio de API es rompiente. El nombre del campo cambia de status a service_status, y los clientes antiguos fallan si no lo manejan.
Qué cambia con un monorepo
Aquí es donde un monorepo suele sentirse más tranquilo. Backend, web y móvil pueden aterrizar en un mismo pull request (o en un set coordinado de commits). CI puede ejecutar tests afectados y puedes marcar un solo release que incluya las tres actualizaciones.
El riesgo principal es social, no técnico: un repo único facilita mergear un cambio rompiente rápidamente, así que tus reglas de revisión deben ser sólidas.
Qué cambia con un polyrepo
Con repos separados, cada app vive en su propio ritmo. El backend puede publicar primero y web y móvil se apresuran a ponerse al día. Si los lanzamientos móviles requieren revisión en la tienda, la “solución” puede tardar días aunque el cambio sea pequeño.
Los equipos suelen resolverlo con más estructura: endpoints versionados, respuestas retrocompatibles, ventanas de deprecación largas y pasos de rollout más claros. Funciona, pero es trabajo continuo.
Si decides según evidencia, mira los últimos meses:
- Si los incidentes suelen venir por versiones desajustadas, favorece coordinación más estrecha.
- Si los lanzamientos son frecuentes y sensibles al tiempo (especialmente móvil), evita cambios rompientes o centralízalos.
- Si los equipos son independientes y rara vez tocan la misma función, el overhead de polyrepo puede valer la pena.
Errores comunes y trampas a evitar
La mayoría no fracasa por elegir la estructura “incorrecta”. Fracasan porque los hábitos diarios añaden fricción hasta que cada cambio parece arriesgado.
El código compartido se convierte en un vertedero
Una librería compartida es tentadora: helpers, tipos, UI, “parches temporales”. Pronto se convierte en el lugar donde el código viejo se esconde y nadie sabe qué es seguro cambiar.
Mantén el código compartido pequeño y estricto. “Compartido” debe significar usado por muchos equipos, revisado cuidadosamente y cambiado con intención.
Acoplamiento fuerte mediante suposiciones ocultas
Incluso con repos separados, los sistemas pueden estar fuertemente acoplados. El acoplamiento solo se traslada a suposiciones: formatos de fecha, valores de enums, reglas de permisos y “este campo siempre está presente”.
Ejemplo: móvil trata status = 2 como “Aprobado”, web lo trata como “Confirmado”, backend cambia el orden del enum y todo se rompe de forma aparentemente aleatoria.
Evita esto documentando contratos (qué significan los campos, qué valores están permitidos) y tratándolos como reglas de producto, no trivia.
Propiedad poco clara
Cuando todos pueden cambiar cualquier cosa, las revisiones se vuelven superficiales y los errores se cuelan. Cuando nadie posee un área, los bugs se quedan semanas.
Define propietarios para web, móvil, backend y módulos compartidos. La propiedad no bloquea contribuciones; asegura que los cambios tengan los ojos adecuados.
CI que crece sin poda
CI suele empezar pequeño y luego cada incidente añade un job “por seguridad”. Meses después es lento y caro y la gente lo evita.
Una regla simple ayuda: cada job de CI necesita un propósito claro y un propietario, y debe eliminarse si deja de detectar problemas reales.
Señales de alarma para limpieza incluyen tests duplicados entre jobs, jobs que permanecen en rojo días, “cambios rápidos” que tardan más en verificarse que en construirse y pipelines que disparan builds móviles por cambios solo en backend.
Coordinación de releases basada en conocimiento tribal
Si los releases dependen de una persona que recuerda el orden correcto y los trucos secretos, publicarás más lento y romperás más cosas.
Escribe los pasos de release, hazlos repetibles y automatiza las comprobaciones aburridas. Incluso si tu tooling genera backends y clientes consistentes, sigues necesitando reglas claras de release.
Comprobaciones rápidas antes de decidir monorepo o polyrepo
Antes de reorganizar repos, comprueba cómo despliega tu equipo hoy. La meta no es una estructura perfecta, sino menos sorpresas cuando un cambio toca web, móvil y backend.
Haz cinco preguntas:
- Independencia de despliegue: ¿Puedes lanzar un fix en backend sin forzar una actualización móvil el mismo día?
- Reglas de cambio de API: ¿Tenéis un contrato escrito para deprecaciones y cuánto tiempo se mantiene el comportamiento antiguo?
- Disciplina en código compartido: ¿Las librerías compartidas (componentes UI, clientes API, reglas de negocio) se revisan y versionan consistentemente?
- CI que ejecuta lo que importa: ¿Puede CI identificar qué cambió y ejecutar builds/tests solo para las partes afectadas?
- Una vista de releases: ¿Existe un lugar para ver qué sale en web, móvil y backend, con propietarios y fechas?
Ejemplo simple: se añade un campo “address” al checkout. Si el backend publica primero, la app móvil antigua debería seguir funcionando. Eso suele significar que la API acepta tanto cargas antiguas como nuevas durante un tiempo y que las actualizaciones de cliente son opcionales, no obligatorias.
Próximos pasos: reducir el trabajo de coordinación y publicar con confianza
La meta no es la “estructura correcta” del repos. Es menos handoffs, menos sorpresas y menos momentos de “espera, ¿qué versión está en producción?”.
Escribe un breve registro de decisión: por qué elegiste el enfoque actual, qué esperas mejorar y qué tradeoffs aceptas. Revísalo cada 6–12 meses o antes si cambia el tamaño del equipo o el ritmo de releases.
Antes de mover archivos, elige el cambio más pequeño que quite un dolor real:
- Añade y sigue reglas de versionado para paquetes compartidos.
- Define contratos API y compruébalos con tests de contrato en CI.
- Acordad una checklist de release común para web, móvil y backend.
- Usa entornos preview para cambios que tocan varias partes.
- Establece presupuestos de tiempo de CI (por ejemplo: checks de PR por debajo de 15 minutos).
Si el acoplamiento entre bases de código es el cuello de botella real, reducir el número de lugares que deben cambiar puede importar más que la disposición de repos. Algunos equipos logran esto moviendo más lógica y modelado de datos a una única fuente de verdad.
Si quieres explorar ese enfoque, AppMaster (appmaster.io) está diseñado para generar servicios backend, apps web y móviles nativas con modelos de datos y lógica de negocio compartida. Una forma de bajo riesgo para evaluarlo es construir primero una herramienta interna pequeña y decidir según cuánto trabajo de coordinación elimine.
El camino seguro es deliberadamente aburrido: documenta la decisión, reduce el acoplamiento, automatiza las comprobaciones y cambia la estructura de repos solo cuando los números indiquen que ayudará.
FAQ
Comienza por observar con qué frecuencia una sola función obliga a cambiar web, móvil y backend. Si la mayoría del trabajo es transversal y la coordinación es tu principal dolor, un monorepo o un enfoque de “contrato único” fuerte suele reducir las roturas. Si los equipos rara vez tocan las mismas áreas y necesitan control independiente de acceso y despliegue, un polyrepo puede funcionar bien con reglas estrictas de compatibilidad.
La deriva de API, desajustes de versiones de librerías compartidas y diferencias en el ritmo de despliegue (sobre todo la demora de las tiendas de apps) son los culpables habituales. La solución es planificar para versiones mixtas en el mundo real, no para despliegues perfectamente sincronizados, y hacer que los cambios que rompen sean raros y deliberados.
Trata el esquema de la API como la fuente de la verdad y genera clientes a partir de él para que los desajustes fallen en la compilación, no en QA o producción. Prefiere cambios aditivos primero, depreca campos después y mantén una ventana de compatibilidad corta cuando sea necesario renombrar o eliminar algo.
Apunta a actualizaciones pequeñas y regulares (una cadencia semanal supera a una trimestral) y exige aprobación explícita para cambios que rompen. Incluye una breve nota de migración con cada cambio y define “hecho” como “web, móvil y backend compilan y pasan tests”, no solo un repositorio.
Por defecto, versiones por servicio con una regla de compatibilidad clara: qué versiones del backend soportan qué versiones de clientes y durante cuánto tiempo. Un tren de lanzamientos compartido puede funcionar al principio, pero las demoras móviles lo hacen doloroso salvo que aceptes esperar el ritmo de las tiendas de apps.
Mantén el backend compatible para que las versiones antiguas de la app móvil sigan funcionando mientras los usuarios se actualizan. Usa campos aditivos, no elimines comportamientos antiguos prematuramente y apóyate en feature flags para desplegar cambios visibles en el cliente de forma gradual.
Haz que sea el trabajo explícito de alguien: suele ser un tech lead, un release manager o un product owner con apoyo de ingeniería. La meta es un calendario simple y repetible y una regla clara para decidir qué hacer ante retrasos (retener el cambio vs mantener compatibilidad), no un proceso pesado.
Por defecto, construye y prueba solo lo que cambió y cachea todo lo que puedas. Separa comprobaciones rápidas (cada commit) de comprobaciones lentas (rama principal, nocturnas o pre-lanzamiento) para que los desarrolladores reciban feedback sin pagar el coste completo de pruebas en cada cambio.
Usa filtros por ruta y un enfoque “solo lo afectado” para no reconstruir el mundo por un cambio pequeño. Si un módulo compartido cambia, ejecuta checks solo para las apps que dependen de él, y mantiene claras las reglas de propiedad y revisión para que un repositorio no se convierta en el cajón de sastre de todos.
Estandariza herramientas y plantillas de CI entre repos para que cada uno no reinventen pasos, caches y convenciones. Añade una comprobación de integración que valide contratos clave entre releases y fija versiones de toolchains para evitar sorpresas del tipo “funciona en un repositorio pero no en otro”.


