Por qué un monorepo
Cuando un proyecto crece, la pregunta no es si necesitas un monorepo, sino cuando. Senales de que es momento:
- Tienes multiples apps que comparten código (web, admin, mobile)
- Copias archivos entre repositorios
- Los cambios en una libreria requieren actualizar varios repos
- Tu equipo crece y necesitas boundaries claros entre módulos
Un monorepo no significa "todo en un archivo". Significa multiples proyectos en un repositorio con herramientas que los conectan inteligentemente.
Por qué Nx para Angular
Nx es el toolkit de monorepo más maduro para el ecosistema Angular. Fue creado por ex-miembros del equipo de Angular en Google y ofrece:
- Cache inteligente: No rebuilds cosas que no cambiaron
- Grafo de dependencias: Visualiza las relaciones entre proyectos
- Generadores: Scaffolding de apps, librerias y componentes
- Affected commands: Solo ejecuta tests/builds de lo que cambio
- Plugins oficiales: Angular, React, Node, Nest, y más
Paso 1: Crear el workspace
Usa el primer bloque de código para crear tu workspace. El preset angular-monorepo configura todo lo necesario para Angular con las mejores prácticas de Nx.
Estructura del workspace
Despues de la creación, tu workspace se ve así:
mi-workspace/
apps/
web-app/
src/
app/
assets/
index.html
main.ts
styles.css
project.json
tsconfig.app.json
libs/
nx.json
tsconfig.base.json
package.jsonLa separacion fundamental es:
- apps/: Aplicaciones desplegables. Deben ser delgadas (solo bootstrapping y routing)
- libs/: Librerias reutilizables. Aqui vive la lógica real
Paso 2: Crear librerias
Las librerias son el corazon de un monorepo Nx. Sigue una taxonomia clara. El segundo bloque de código muestra como crear diferentes tipos.
Taxonomia de librerias
Organiza tus librerias en estas categorias:
| Tipo | Proposito | Ejemplo |
|---|---|---|
| feature | Funcionalidad completa con routing | libs/features/courses |
| ui | Componentes de UI reutilizables | libs/shared/ui |
| data-access | Servicios, state management | libs/shared/data-access |
| útil | Funciones puras, helpers | libs/shared/utils |
| models | Interfaces, types, enums | libs/shared/models |
Path aliases
Nx configura automaticamente path aliases en tsconfig.base.json:
{
"compilerOptions": {
"paths": {
"@mi-workspace/shared/ui": ["libs/shared/ui/src/index.ts"],
"@mi-workspace/shared/models": ["libs/shared/models/src/index.ts"],
"@mi-workspace/shared/utils": ["libs/shared/utils/src/index.ts"],
"@mi-workspace/features/courses": ["libs/features/courses/src/index.ts"]
}
}
}Esto permite importar entre librerias de forma limpia:
import { ButtonComponent } from '@mi-workspace/shared/ui';
import { Course } from '@mi-workspace/shared/models';
import { slugify } from '@mi-workspace/shared/utils';Paso 3: Mover lógica a librerias
La regla de oro: las apps deben ser delgadas. Toda la lógica se mueve a librerias. Tu app.routes.ts solo conecta features:
import { Routes } from '@angular/router';
export const appRoutes: Routes = [
{
path: '',
loadComponent: () =>
import('@mi-workspace/features/home')
.then(m => m.HomeComponent),
},
{
path: 'cursos',
loadChildren: () =>
import('@mi-workspace/features/courses')
.then(m => m.coursesRoutes),
},
{
path: 'blog',
loadChildren: () =>
import('@mi-workspace/features/blog')
.then(m => m.blogRoutes),
},
];Paso 4: Boundaries y reglas
Module boundaries
Nx permite definir reglas sobre que librerias pueden importar de cuales. Configura tags en cada project.json:
{
"name": "features-courses",
"tags": ["scope:courses", "type:feature"]
}Y reglas en .eslintrc.json:
{
"rules": {
"@nx/enforce-module-boundaries": [
"error",
{
"depConstraints": [
{
"sourceTag": "type:feature",
"onlyDependOnLibsWithTags": ["type:ui", "type:data-access", "type:útil", "type:models"]
},
{
"sourceTag": "type:ui",
"onlyDependOnLibsWithTags": ["type:útil", "type:models"]
},
{
"sourceTag": "type:útil",
"onlyDependOnLibsWithTags": ["type:models"]
},
{
"sourceTag": "type:models",
"onlyDependOnLibsWithTags": []
}
]
}
]
}
}Esto garantiza que:
- Features pueden usar UI, data-access, utils y models
- UI solo puede usar utils y models
- Utils solo puede usar models
- Models no depende de nada
Por qué importan las boundaries
Sin boundaries, un monorepo se convierte rapidamente en un espagueti. Las dependencias circulares aparecen, los cambios en una libreria rompen todo, y el grafo se vuelve inmanejable. Las boundaries previenen esto desde el primer dia.
Paso 5: Cache y affected
Cache local
Nx cachea los resultados de build, test y lint. Si ejecutas nx build web-app y nada cambio, el resultado se sirve de cache instantaneamente:
# Primera vez: build completo
npx nx build web-app
# => 45 segundos
# Segunda vez sin cambios: cache hit
npx nx build web-app
# => 0.3 segundos (desde cache)Nx Cloud (cache remota)
Nx Cloud permite compartir cache entre desarrolladores y CI:
npx nx connectCuando un companero ya buildeo una libreria, tu obtienes el resultado de cache remota sin compilar. En equipos grandes, esto ahorra horas de CI al dia.
Affected commands
Los comandos affected solo ejecutan tareas para los proyectos impactados por los cambios recientes:
# Solo testea lo que cambio
npx nx affected -t test
# Solo buildea lo que cambio
npx nx affected -t build
# Solo lintea lo que cambio
npx nx affected -t lintPaso 6: CI optimizado
GitHub Actions con Nx
name: CI
on: [push, pull_request]
jobs:
main:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-node@v4
with:
node-versión: 22
cache: npm
- run: npm ci
- uses: nrwl/nx-set-shas@v4
- run: npx nx affected -t lint test buildEl step nx-set-shas determina automaticamente que cambio entre el commit actual y el anterior, para que affected funcione correctamente.
Paso 7: Agregar una segunda app
La ventaja del monorepo se materializa cuando agregas otra app:
npx nx generate @nx/angular:application admin-panel \
--directory=apps/admin-panel \
--routing=true \
--style=cssEsta nueva app puede importar las mismas librerias compartidas:
// En admin-panel/src/app/app.routes.ts
import { ButtonComponent } from '@mi-workspace/shared/ui';
import { Course } from '@mi-workspace/shared/models';Cambias el componente de UI una vez y ambas apps se actualizan.
Visualizar el grafo
Nx tiene una herramienta de visualización integrada:
npx nx graphEsto abre un navegador con el grafo interactivo de dependencias. Puedes ver que libreria depende de cual, identificar dependencias circulares y entender el impacto de un cambio.
Errores comunes
Librerias demasiado granulares
No crees una libreria por componente. Agrupa por dominio. Una libreria shared/ui con 15 componentes es mejor que 15 librerias de un componente cada una.
Apps con lógica
Si tu app tiene más de routes y bootstrapping, estas haciendo algo mal. Mueve esa lógica a una libreria feature.
No configurar boundaries
Un monorepo sin boundaries es peor que repos separados. Configura las reglas desde el dia uno.
Ignorar el cache
Si tu CI no usa Nx cache o Nx Cloud, estas desperdiciando la ventaja principal del monorepo.
Conclusion
Nx transforma la gestion de proyectos Angular a nivel profesional. El cache inteligente, los affected commands y las module boundaries te dan estructura y velocidad que seria muy difícil de lograr con herramientas caseras.
Empieza con una app y unas pocas librerias. A medida que tu proyecto crece, el monorepo escala contigo sin convertirse en un caos.



Comentarios (0)
Inicia sesión para comentar