5 apps en un solo repositorio: el monorepo Turborepo de un desarrollador independiente
Cómo montar un monorepo con Turborepo para gestionar varias apps y webs en un solo repositorio. Configuraciones compartidas, ahorro de builds con caché y despliegue por app, desde un enfoque práctico.
Lo esencial
Cuando construyes varias apps en solitario, las configuraciones se dispersan. Con un monorepo Turborepo compartes eslint y tsconfig desde packages, la caché de turbo evita reconstruir las apps que no cambiaron, y con --filter despliegas app por app.
En esta página
Cuando construyes apps en solitario, los repositorios se multiplican sin parar. Una app, una web, otra app... y terminas copiando y pegando la configuración de eslint cinco veces. Yo lo junté todo en un solo monorepo.
El verdadero problema son las configuraciones dispersas
Con muchos repositorios, lo que más duele no es el código sino la configuración.
- Copiar eslint, prettier y tsconfig en cada repositorio
- Cambiar una regla y tener que recorrerlos todos para actualizarla
- La UI y las utilidades compartidas son demasiado triviales para publicarlas en npm
El monorepo cambia esto por un modelo donde todo se comparte desde un solo lugar.
Estructura básica
apps/
├── web/ # 랜딩
├── blog/ # 이 블로그
├── wave/ # 오늘의 파도
└── ...
packages/
├── eslint-config/ # 공용 eslint
└── typescript-config/ # 공용 tsconfig
apps/* son los artefactos que se despliegan y packages/* es la configuración y el código que las apps comparten. El tsconfig.json de cada app simplemente hereda.
{ "extends": "@repo/typescript-config/nextjs.json" }
Ahora las reglas se corrigen en un solo sitio: packages.
La caché de turbo es la clave
El arma de verdad de Turborepo es la caché. Si las entradas de una tarea (código fuente y configuración) no cambiaron, reutiliza el resultado anterior tal cual.
turbo run build # 전체 빌드(바뀐 것만 실제로 돎)
turbo run build --filter=blog # blog 앱만
Basta con declarar en turbo.json las dependencias entre tareas y sus salidas.
{
"tasks": {
"build": { "dependsOn": ["^build"], "outputs": [".next/**"] }
}
}
A partir del segundo build, termina en segundos con "FULL TURBO".
Desplegar app por app
Aunque sea un solo repositorio, el despliegue se separa por app. Con Docker puedes usar turbo prune para recortar solo el subárbol de esa app y crear una imagen ligera.
turbo prune blog --docker # blog + 내부 의존성만 남긴 out/ 생성
Este blog también lo recorté así y lo subí a un mini PC con Docker. Esa historia la cuento en el artículo sobre self-hosting.
En resumen
apps/*= artefactos desplegables,packages/*= configuración compartida- tsconfig y eslint se gestionan por herencia desde un solo lugar
- La caché de
turboevita reconstruir las apps que no cambiaron - Despliegue por app con
--filteryprune
Si mantienes varios productos en solitario, el monorepo no es un lujo sino una herramienta de supervivencia.
Preguntas frecuentes
¿A partir de cuántas apps conviene un monorepo?
Con solo pasar de 2 ya conviene, en cuanto aparecen configuraciones compartidas (eslint, tsconfig, UI). La clave es corregir la configuración en un solo lugar y que se aplique a todas las apps.
¿No se vuelve más lento el build?
Al contrario, se vuelve más rápido. turbo cachea el resultado de las tareas cuyas entradas no cambiaron y solo reconstruye las apps modificadas.
Artículos relacionados
- 💻 Desarrollo
Cuando un bucket tiene dos dueños, gana el último que hace apply
Añadí una sola regla de lifecycle en S3 y terraform apply falló. La causa: una estructura en la que dos recursos poseían cada uno por su cuenta la configuración de lifecycle del mismo bucket. El lifecycle de S3 no opera por reglas sino por documento entero, así que el último ganador borra en silencio las reglas del otro.
- 💻 Desarrollo
Los tests estaban en verde, pero la notificación nunca llegó a enviarse
El código que encolaba el job fallaba desde el primer día, siempre. El error se tragaba en un catch y los tests seguían en verde gracias a los mocks. La historia de cómo un solo carácter, dos puntos, mató en silencio tres funcionalidades.
- 💻 Desarrollo
Llegó una alerta diciendo que la base de datos estaba caída. La base de datos nunca se cayó
En un solo día se acumularon cuatro alertas CRITICAL. Un 504, un P2028 de Prisma, un 500 en el admin y 'servicio DATABASE caído'. Abrí primero las métricas de RDS y durante 21 horas seguidas la CPU no pasó del 19.7%, tan tranquila. Lo lento no era la base de datos, sino un viaje de ida y vuelta que cruzaba el Atlántico veinticinco veces, y la alerta de 'caída' se la había fabricado el propio health check.