Llevo tres años peleando con monorepos. Empecé con un repo gigante de Node.js donde todo vivía junto, sin ninguna herramienta de build especial, y llegó un momento en que el CI tardaba 23 minutos en correr. No segundos — minutos. Cada PR era una espera eterna y nadie en el equipo sabía exactamente qué había que tocar para que algo se reconstruyera correctamente.
Entonces empecé a evaluar opciones en serio. La primera semana de febrero usé Turborepo 2.3 en un proyecto interno con mi equipo (somos 6 personas, manejamos tres apps de Next.js y cinco paquetes compartidos). La segunda semana migré todo a Nx 20.x con la misma base de código. Misma infra, mismo equipo, mismos problemas de partida.
Aquí está lo que encontré.
Por Qué el Monorepo Sin Tooling Se Convierte en un Infierno Pasado Cierto Punto
Primero el contexto, porque creo que importa bastante para entender los tradeoffs.
El proyecto que usé para las pruebas es una plataforma SaaS: una app de cliente, un dashboard interno, una API en Express y varios paquetes compartidos: @myapp/ui, @myapp/types, @myapp/utils. Setup clásico. Antes de llegar a cualquiera de las dos herramientas, usábamos workspaces de pnpm con algunos scripts de bash a mano. Funcionaba, pero "funcionar" y "funcionar bien" son cosas muy distintas.
El problema más grande no era el tiempo de build — era que nadie sabía qué dependía de qué. Si alguien tocaba @myapp/utils, el CI corría absolutamente todo. Siempre. Sin excepción. No había forma de que el sistema supiera que la app de cliente no importa utils para nada. El desarrollador que pusheaba un cambio de tres líneas esperaba el mismo tiempo que el que había refactorizado medio sistema.
Eso es lo que tanto Turborepo como Nx intentan resolver: dependency graph + caché inteligente. Pero lo hacen de maneras filosóficamente distintas, y esa diferencia se siente desde el minuto uno.
Turborepo 2.3: La Configuración Te Seduce el Primer Día
La experiencia de onboarding de Turborepo es genuinamente buena. Corrí npx create-turbo@latest y en diez minutos tenía algo funcional. La configuración central vive en turbo.json y es notablemente legible para alguien que llega sin contexto previo:
{
"$schema": "https://turbo.build/schema.json",
"tasks": {
"build": {
"dependsOn": ["^build"],
"outputs": [".next/**", "dist/**"]
},
"lint": {
"dependsOn": [],
"cache": true
},
"test": {
"dependsOn": ["^build"],
"cache": true,
"outputs": ["coverage/**"]
},
"dev": {
"persistent": true,
"cache": false
}
}
}
El ^build en dependsOn es la clave. Significa "primero construye todas mis dependencias". Simple, declarativo, hace exactamente lo que dice. Pasé como 30 minutos leyendo la doc y ya tenía el modelo mental completo. No hubo un momento de "espera, ¿cómo funciona esto realmente?"
El caché local funcionó de maravilla desde el primer intento. Después del primer build completo (que tardó 4 minutos), el segundo tardó 11 segundos. Exactamente 11. Lo medí tres veces porque no me lo creía.
Lo que me decepcionó fue el Remote Cache. La opción oficial es Vercel Remote Cache, gratuita para proyectos personales pero con pricing que escala rápido para equipos. Hay opciones open source — turborepo-remote-cache es un servidor que puedes hostear tú mismo — y funciona, pero no es la experiencia pulida que el resto de Turborepo promete. En nuestro caso usamos AWS y pasé una tarde completa configurando S3 más el servidor de caché. Funciona. Pero es un contraste raro con lo fácil que fue todo lo anterior.
Otra cosa que vale mencionar: Turborepo no tiene opinión sobre cómo estructuras tus paquetes. No genera nada, no sugiere nada, no impone nada. Eso es un arma de doble filo. Si ya sabes lo que estás haciendo, tienes control total. Si estás armando un monorepo desde cero con un equipo mixto, vas a invertir tiempo extra diseñando convenciones que en otras herramientas vienen incluidas.
Mi conclusión práctica con Turborepo: te compra tiempo de build, te cuesta tiempo de configuración de infraestructura. El net positivo existe — es real — pero no es tan instantáneo como la demo inicial hace creer.
Nx 20.x: Más Framework que Herramienta, y Eso Tiene Consecuencias
Nx es una bestia diferente. La primera señal fue el wizard de instalación: npx create-nx-workspace@latest me preguntó si quería un "monorepo integrado" o un "standalone project", qué framework quería usar, si quería habilitar Nx Cloud, y un par de preguntas más. Hay mucha más superficie desde el principio — lo cual no es malo, pero te avisa de cómo va a ser la relación.
El nx.json básico se ve así:
{
"defaultBase": "main",
"targetDefaults": {
"build": {
"dependsOn": ["^build"],
"cache": true,
"outputs": ["{projectRoot}/dist"]
},
"test": {
"cache": true,
"outputs": ["{projectRoot}/coverage"]
}
},
"namedInputs": {
"default": ["{projectRoot}/**/*", "sharedGlobals"],
"sharedGlobals": ["{workspaceRoot}/tsconfig.base.json"],
"production": [
"default",
"!{projectRoot}/**/?(*.)+(spec|test).[jt]s?(x)"
]
}
}
Ojo con namedInputs — esto es algo que Turborepo no tiene de forma nativa con la misma granularidad. Puedes definir exactamente qué archivos invalidan el caché de cada tarea. En teoría es poderoso. En la práctica, tardé tres días en entender bien cómo configurarlo sin romper el caché en situaciones edge. No es que sea difícil — es que hay más piezas que ensamblar correctamente.
Donde Nx brilla de verdad es en el grafo de dependencias. nx graph abre una visualización interactiva en el browser que muestra exactamente qué depende de qué. La primera vez que lo vi pensé "okay, esto justifica el setup más largo". Con seis paquetes y tres apps, el grafo ya resulta útil para onboardear a alguien nuevo. Me imagino que con 40 proyectos es directamente indispensable.
Los generators son otra ventaja concreta. nx generate @nx/next:app nueva-app crea una app con toda la configuración integrada en el workspace — tsconfig extendido, configuración de tests, lint, todo. Con Turborepo harías eso a mano o escribirías tus propios scripts. Cuando tienes un equipo que constantemente está creando nuevos paquetes o apps, la consistencia que esto compra es real.
Here is the thing: Nx asume que vas a vivir en su ecosistema. Si adoptas los generators, la CLI, los executors, tienes un entorno muy cohesivo. Pero si quieres usar algo que Nx no soporta nativamente — un bundler exótico, un runner de tests menos popular — la experiencia se complica. Los plugins de la comunidad existen, pero la calidad varía bastante dependiendo de a quién le toque mantener ese plugin el año que viene.
El Jueves que Nx Me Rompió el CI en Cuatro Pipelines Distintos
Aquí viene la parte honesta.
Estaba en la segunda semana de pruebas, habiendo migrado el proyecto a Nx. Todo iba bien en local. Hice push un jueves por la tarde — no un viernes, lo juro, aprendí esa lección en otro contexto — y los cuatro pipelines del repo fallaron todos al mismo tiempo con el mismo error:
NX The "inputs" for "build" in project.json of app-cliente are invalid.
El problema resultó ser una incompatibilidad entre cómo Nx 20.2 interpreta los namedInputs heredados desde nx.json vs. los definidos localmente en el project.json de cada app. Había un issue abierto en GitHub que describía exactamente mi caso. La solución era actualizar a 20.3 (que salió dos días después) o añadir un override explícito en cada project.json.
Elegí el override porque no quería actualizar en medio de la evaluación y perder la comparabilidad de datos. Eso significó tocar seis archivos distintos para arreglar algo que funcionaba perfectamente en la versión anterior.
No fue catastrófico. Pero me hizo pensar: con Turborepo, en dos semanas de uso, no tuve ningún error parecido. La configuración es más simple, hay menos lugares donde algo puede salir mal de formas sutiles. Uno de mis colegas — que lleva más tiempo con Nx que yo — me dijo que este tipo de cosas pasa menos a medida que te familiarizas con el sistema y aprendes qué no tocar. Puede ser. Pero "aprende qué no tocar" no es el tipo de conocimiento que quieres que tu equipo junior tenga que acumular de la manera difícil.
Lo que sí me sorprendió positivamente, en retrospectiva: el error fue descriptivo. Nx al menos me dijo exactamente qué proyecto fallaba y en qué campo. He visto errores de build mucho más oscuros en otras herramientas.
Mi Recomendación Según el Tamaño Real de Tu Equipo
Después de dos semanas, una migración, un bug de CI y bastantes horas leyendo docs, llegué a una lectura bastante clara.
Equipos de menos de 10 personas con menos de 10 proyectos en el monorepo: Turborepo es suficiente y mucho menos overhead. El tiempo que ahorras en setup y mantenimiento es real. El caché local funciona excelente, y si ya estás en Vercel, el Remote Cache es prácticamente gratis. El modelo mental es simple — puedes onboardear a alguien nuevo en una tarde.
La ecuación cambia cuando el equipo crece. Múltiples squads tocando el mismo repo, o más de 15-20 proyectos en vuelo, y Nx empieza a tener sentido. Los generators mantienen consistencia entre proyectos sin depender de que cada desarrollador recuerde copiar el boilerplate correcto. El grafo de dependencias deja de ser un nice-to-have.
Hay un tercer factor que casi nadie menciona: el stack. Si todo tu repo es Next.js + TypeScript, ambas herramientas funcionan muy bien. Si tienes una mezcla de React, Go, Python scripts y herramientas diversas, Nx tiene más plugins oficiales y más soporte para casos heterogéneos. Turborepo es agnóstico, pero eso también significa que conectas más piezas tú mismo.
No he podido validar completamente cómo escala Nx más allá de los 50 proyectos — nunca he operado a esa escala personalmente — pero la arquitectura claramente fue diseñada pensando en ese tamaño.
Mi recomendación real, sin el "depende de tu caso" de rigor: empieza con Turborepo. Es más rápido de adoptar, más fácil de mantener para equipos de hasta 15 personas, y el modelo mental te va a ahorrar problemas el 80% del tiempo. Si en seis meses tu repo crece hasta el punto donde sientes que necesitas generators, visualización de grafo y soporte multi-framework de verdad, ese es el momento de evaluar Nx — no antes.
Migrar de Turborepo a Nx no es trivial, pero tampoco es el apocalipsis. Lo que sí es costoso es adoptar Nx antes de tiempo y pasar meses peleando con su complejidad cuando Turborepo habría resuelto tu problema con la mitad del esfuerzo.
Nx tiene más features. Turborepo tiene menos sorpresas. En 2026, con proyectos que van a toda velocidad y equipos que no quieren leer 40 páginas de docs para configurar el CI, las sorpresas me salen más caras que los features.
Top comments (0)