El mensaje de Slack llegó a las 22:47 de un viernes. Un tester había pagado en el sandbox de Stripe, el webhook se disparó, la fila de suscripción apareció en la base de datos, y el web app seguía diciendo "Plan gratuito."

Sabía dónde mirar. Había escrito la feature tres semanas antes y todavía recordaba su forma. Lo que no recordaba, porque nadie lo recuerda hasta que duele, es que la palabra en pantalla y el valor en la API no se mantienen alineados solos.

El bug nunca estuvo en un solo repositorio

La API guardaba el estado del plan como un enum entero. El web app mapeaba ese entero a una etiqueta con un archivo de constantes compartido. El admin panel tenía su propia columna con una badge legible.

Los tres eran correctos el lunes. El viernes alguien había añadido un estado de prueba nuevo en la migración de la API, actualizado el copy del web app, y olvidado el color de la badge en el admin. Tres ediciones pequeñas en tres sitios que debían representar el mismo hecho.

En un setup multi-repo eso son tres pull requests, tres revisiones si tienes suerte, tres pipelines de deploy, y una ventana en la que producción muestra tres verdades distintas según qué URL abras. Un viernes por la noche no tienes paciencia para esa ventana. Tienes a un tester refrescando la página de facturación y preguntándose si tu producto funciona.

En un monorepo de template, las cuatro aplicaciones viven juntas: marketing site, web app de cliente, admin panel y API. Los contratos compartidos están en una sola carpeta. La marca del producto y la lista de locales están en configuración centralizada. Cuando cambia el enum, TypeScript y C# ven la misma fuente de verdad en un solo commit.

Ese arreglo del viernes fue una rama, un diff, un push. La API devolvió el estado nuevo, el web app leyó el mapeo compartido, el admin panel recogió el mismo nombre de enum. Sin puzzle de orden de deploy. Sin adivinar qué servicio terminó primero.

Lo que la gente teme de los monorepos

La objeción que más escucho es ruido. Cambias el color de un botón en el hero del marketing y el CI corre tests del admin panel. Preocupación válida, y también resuelta si el pipeline está acotado.

Un pipeline de CI bien acotado no trata cada archivo igual. Un cambio en la app del cliente no tiene que bloquear un spec del marketing site que no toca contratos compartidos. El objetivo no es un job gigante que corre para siempre. El objetivo es un solo sitio donde puedes buscar en todo el producto cuando un bug cruza fronteras.

La segunda objeción es control de acceso. "Los contratistas de marketing no deberían ver código de billing." Cierto en equipos grandes. Para un fundador solo o una dupla, todos ya ven todo porque todos son todos. Separar repositorios antes de tener un problema de permisos compra pureza organizativa al precio de coherencia un viernes por la noche.

La tercera es miedo a herramientas: "Los monorepos necesitan Nx o Turborepo o scripts custom." A veces sí a escala. A escala de lanzamiento necesitas un manifiesto de paquetes en la raíz que sepa correr cada app, disciplina de un solo lockfile, y el hábito de poner tipos compartidos en una carpeta en vez de copiar interfaces. Un template mantenido trae ese layout para que no lo inventes en la semana dos.

El momento en que el monorepo se paga solo

Nunca es en el primer commit. El primer commit se siente pesado porque el árbol de carpetas es grande.

Se paga la primera vez que una feature toca más de una superficie. Billing toca el handler del webhook en la API, la página de suscripción del cliente, la lista de suscripciones del admin, y a menudo una línea de copy en la tabla de precios del marketing. La autenticación toca cada app más configuración CORS más plantillas de email.

Cuenta las superficies. Ese es el número de repositorios que te ofreces a mantener alineados si separas pronto.

Un monorepo no elimina coordinación. Mueve la coordinación al historial de Git en vez de a tu calendario. Ves, en un diff, que el handler del webhook y el string de la UI cambiaron juntos. La revisión de código, incluso la auto-revisión a la mañana siguiente, atrapa el drift antes que los usuarios.

Lo que un monorepo no te da

No reemplaza decisiones de producto. Sigues eligiendo si los usuarios en prueba ven features premium. Sigues eligiendo si el admin puede cancelar una suscripción en nombre del cliente. La forma del repositorio no responde esas preguntas. Solo hace visibles en un solo sitio las consecuencias de tus respuestas.

Tampoco reemplaza independencia de deploy. El marketing site, las dos apps del cliente y la API pueden desplegarse en destinos separados. Mismo repo, varios destinos de deploy. El monorepo es alineación de código fuente, no un solo binario.

Y no es complejidad gratis para siempre. Si creces hacia equipos separados con trenes de release distintos, sacar un bounded context puede tener sentido. La mayoría de productos nunca llegan a ese día. La mayoría sí llegan al día en que un usuario de pago encuentra una discrepancia entre lo que dice la factura y lo que muestra el dashboard.

Por qué importa ahora que construir se volvió barato

Generar una página React o un controller en C# lleva minutos ahora. Lo caro es cablear la página, el controller, la migración, la vista del admin y el copy del email para que sigan significando lo mismo después de tu tercera iteración.

Un modelo puede escribir cada archivo aislado. No puede, por sí solo, garantizar que ese aislamiento sobreviva al contacto con producción. Un monorepo con contratos compartidos es cómo le das al modelo, y a ti, un solo mapa.

Un monorepo con contratos compartidos es cómo te das a ti mismo, y a cualquier agente que te ayude, un solo mapa.

El arreglo del viernes que describí no es un argumento de venta porque sea glamuroso. Es trabajo ordinario que se vuelve caro cuando el layout del repositorio pelea contigo.

Si estás eligiendo dónde gastar las semanas del lanzamiento, gástalas en la feature que solo les importa a tus clientes. Deja que el repositorio defienda la coherencia por su cuenta.