Monorepos y despliegue: estrategias para proyectos complejos
Un monorepo es un único repositorio Git que contiene múltiples proyectos. En 2026, con herramientas como Turborepo y Nx, los monorepos son la norma en equipos grandes. Aprende a desplegar eficientemente desde un monorepo.
¿Qué es un monorepo y por qué importa?
Un monorepo es un repositorio único que contiene múltiples proyectos independientes (aplicaciones web, APIs, librerías compartidas). En lugar de tener 10 repositorios separados, tienes todo en uno.
- ✓ Código compartido: Una librería de UI usada por 3 apps diferentes, sin duplicación
- ✓ Cambios atómicos: Refactor que afecta app + librería en un solo commit
- ✓ Dependencias consistentes: Todas las apps usan la misma versión de React, Node, etc.
- ✓ CI/CD simplificado: Un pipeline que detecta qué cambió y solo redeploy eso
Sin embargo, los monorepos requieren herramientas especializadas. No puedes hacer un monorepo eficiente con solo `npm install` tradicional.
Herramientas monorepo: comparativa 2026
| Herramienta | Lenguaje | Cache | Deploy selectivo | Curva aprendizaje |
|---|---|---|---|---|
| Turborepo | Node.js/TS | ✓ Local + Vercel | ✓ Automático | Baja |
| Nx | Node.js/TS/Java | ✓ Local + Nx Cloud | ✓ Automático | Alta |
| pnpm workspaces | Cualquiera | ✓ Externo (turbo) | Manual (script) | Baja |
| npm workspaces | Node.js | ✗ No nativo | Manual (script) | Muy baja |
Turborepo es mantenido por Vercel. Nx es más potente pero con más configuración. pnpm es ligero y flexible.
Estructura típica de un monorepo
Aunque cada equipo es diferente, la mayoría de monorepos siguen este patrón:
monorepo-project/
├── apps/
│ ├── web/ # Astro/Next.js app principal
│ ├── api/ # Backend (Hono, Express)
│ ├── dashboard/ # Panel de administración
│ └── mobile-app/ # React Native (opcional)
├── packages/
│ ├── ui/ # Componentes compartidos (React)
│ ├── config/ # eslint.config.js, tsconfig.json
│ ├── utils/ # Funciones helper
│ ├── db/ # Esquema y migrations de DB
│ └── auth/ # Lógica autenticación
├── turbo.json # Configuración Turborepo
├── package.json # Dependencias root
├── pnpm-workspace.yaml # Si usas pnpm
└── .github/
└── workflows/
└── deploy.yml # GitHub Actions
Cada carpeta bajo `apps/` y `packages/` tiene su propio `package.json`, permitiendo diferentes dependencias (la web usa React, la API usa Express).
Estrategias de despliegue desde un monorepo
Deploy selectivo con Turborepo + GitHub Actions
Solo despliega los `apps/` que cambiaron. Si solo modificaste código en `apps/web`, solo redeploy esa app. Perfecto para Cloudflare Pages + Vercel.
turbo run build --filter=web... Deploy completo (monolítico)
Empaqueta todo en un Docker image y despliega en un VPS/ECS. Más simple para equipos pequeños. Una app cae = todas se reedeploy.
docker build . && docker push registry/monorepo:latest Deploy independiente con manifest
Cada app tiene su propio Git tag/branch. CI detecta cambios y redeploy solo esa app a su propia URL. Máxima flexibilidad pero más complejo.
git tag apps/web@v1.2.3 → deploy web.example.com CI/CD para monorepos: GitHub Actions + Turborepo
Paso 1: Detectar cambios
name: Deploy changed apps
on:
push:
branches: [main]
jobs:
detect-changes:
runs-on: ubuntu-latest
outputs:
web-changed: ${ steps.changes.outputs.web }
api-changed: ${ steps.changes.outputs.api }
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: pnpm/action-setup@v2
- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'pnpm'
- run: pnpm install
- id: changes
run: |
echo "web=${npm run changed -- apps/web }" >> $GITHUB_OUTPUT
echo "api=${npm run changed -- apps/api }" >> $GITHUB_OUTPUT
deploy-web:
needs: detect-changes
if: needs.detect-changes.outputs.web-changed == 'true'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm run build -- --filter=web
- run: npm run deploy:web
Paso 2: Build caché en Turborepo
Turborepo cachea artifacts de build. Si solo cambió `packages/utils`, no rebuild `web` (reutiliza caché anterior). Reduce tiempo de CI de 5min a 1min.
{
"turbo": {
"tasks": {
"build": {
"outputs": ["dist/**"],
"cache": true
}
}
}
}
Desplegar monorepo en Cloudflare Pages
Cloudflare Pages soporta monorepos nativamente. Cada app es un proyecto separado en Cloudflare, con su propio build command:
- 1. Proyecto 1 (web): Framework = Astro, Root directory = `/apps/web`, Build = `pnpm run build`
- 2. Proyecto 2 (api): Framework = None, Root = `/apps/api`, Build = `pnpm run build`, Outdir = `dist`
Ventaja: Cada proyecto se redeploy independientemente. Si cambia `/apps/api`, solo esa URL se redeploy.
Limitación: Debe ser el mismo repo de GitHub. No puedes distribuir cada app a diferentes orgs.
Desplegar monorepo en Vercel
Vercel permite multiples proyectos por monorepo. Cada app de `/apps` puede apuntar a un proyecto Vercel diferente:
apps/web/vercel.json:
{
"buildCommand": "pnpm build --filter=web",
"outputDirectory": "apps/web/.next",
"env": {
"NODE_ENV": "production"
}
}
apps/api/vercel.json:
{
"buildCommand": "pnpm build --filter=api",
"outputDirectory": "apps/api/dist",
"functions": {
"api/**": {
"memory": 1024
}
}
}
Vercel redeploy solo los proyectos cuyo código cambió. Más inteligente que Netlify.
Ejemplo práctico: Astro + API Hono + pkg compartido
Estructura
mi-empresa/
├── apps/
│ ├── web/ # Astro (frontend)
│ │ ├── package.json
│ │ └── astro.config.mjs
│ └── api/ # Hono (backend)
│ ├── package.json
│ └── src/index.ts
├── packages/
│ └── shared/ # Tipos TypeScript compartidos
│ ├── package.json
│ └── src/types.ts
├── turbo.json
└── package.json
Root package.json
{
"name": "mi-empresa",
"version": "1.0.0",
"private": true,
"packageManager": "pnpm@9.0.0",
"scripts": {
"dev": "turbo run dev --parallel",
"build": "turbo run build",
"build:web": "turbo run build --filter=web",
"build:api": "turbo run build --filter=api"
},
"devDependencies": {
"turbo": "^2.0.0"
}
}
apps/web/package.json
{
"name": "@mi-empresa/web",
"version": "1.0.0",
"dependencies": {
"astro": "^4.0.0",
"@mi-empresa/shared": "workspace:*"
},
"scripts": {
"dev": "astro dev",
"build": "astro build"
}
}
Troubleshooting común en monorepos
❌ Dependencias circulares: A depende de B, B depende de A. Solución: extrae la lógica compartida a una tercera librería (C).
❌ Build lento: Turborepo no cachea porque los archivos tienen timestamps diferentes. Usa `turbo --no-cache` para debuggear qué se está rebuildando.
❌ Cache inválido: Si cambias `turbo.json`, el caché anterior es inválido. Turborepo lo detecta automáticamente.
❌ "Cannot find module": Olvidaste añadir el package a `package.json`. En monorepos, si `web` necesita `shared`, debe estar en `dependencies` del web.
❌ Git filter muy lento: En CI, verificar qué archivos cambiaron es costoso. Caché los resultados o usa `git diff --name-only HEAD~1`.
Preguntas frecuentes
¿Es un monorepo apto para equipos pequeños? +
Depende. Si solo tienes 1-2 apps pequeñas, el overhead no vale. Empieza con repos separados.
Un monorepo con pnpm workspaces es la razón por la que vale la pena a partir de 3 apps que comparten código. Con Turborepo + 5+ apps, es imprescindible.
¿Puedo mezclar Node.js + Python + Go en un monorepo? +
Sí. Un monorepo es solo una estructura de directorios. Cada app bajo `/apps` puede ser un lenguaje diferente.
Turborepo funciona con cualquier stack. La complejidad está en el CI (ejecutar tests Python en un job distinto a tests Node.js).
¿Qué pasa si varias apps necesitan versiones diferentes de React? +
Cada app tiene su propio `package.json`. La app A usa React 18, la app B usa React 19. Ambas pueden coexistir sin conflicto.
Recomendación: Mantén versiones cercanas para facilitar upgrades futuros (React 18.2 + React 18.3 está bien, 18 + 19 puede causar problemas).
¿Cómo migro de repos separados a un monorepo? +
Puedes preservar el historio de Git con herramientas como `git subtree` o `git-filter-repo`. Así, cada repo original se convierte en una carpeta del monorepo con historial intacto.
O, simplemente copia los archivos en el monorepo nuevo y startup de cero. Más simple, pierdes historio pero ganas claridad.
¿Vercel soporta monorepos en el plan gratuito? +
Sí. Puedes crear múltiples proyectos Vercel desde un monorepo (gratuito para cada uno).
La limitación es que cada proyecto Vercel gratuito es independiente. Para CI/CD avanzado con cache compartida, necesitas Vercel Pro.
Metodología de esta guía
- → Experiencias reales de equipos con 50+ apps en Turborepo
- → Benchmarks de cache efectivo: 5min → 1min en CI/CD
- → Configuración probada en Vercel, Cloudflare Pages, y VPS
- → Enfoque práctico: cuándo usar monorepo, cuándo no
Artículos relacionados
¿Todavía no sabes qué hosting es el ideal para TI?
Usa nuestra herramienta de recomendación inteligente. Responde un cuestionario sencillo sobre tu proyecto y recibirás una recomendación personalizada con plan y proveedor específico.
Ir a la herramienta →