Conceptos

Monorepos

Estrategia de organización de código donde múltiples proyectos coexisten en un único repositorio, compartiendo dependencias, configuración y herramientas de build.

evergreen#architecture#tooling#dx#git

Un monorepo es un repositorio único que contiene múltiples proyectos distintos con relaciones bien definidas entre ellos. No es simplemente «todo el código en una carpeta» — es una estrategia arquitectónica con herramientas especializadas.

¿Qué problema resuelve?

En un modelo polyrepo (un repositorio por proyecto), los equipos enfrentan:

  • Dependency hell — sincronizar versiones entre repos es manual y propenso a errores
  • Cambios atómicos imposibles — un refactor que toca 3 repos requiere 3 PRs coordinados
  • Duplicación de configuración — ESLint, TypeScript, CI/CD copiados en cada repo
  • Descubrimiento difícil — ¿dónde está el código que necesito? ¿qué versión usa el otro equipo?

El monorepo centraliza todo en un solo lugar con herramientas que manejan la complejidad.

¿Cuándo usarlo?

Buena opción cuando:

  • Múltiples paquetes comparten código común (tipos, utilidades, componentes)
  • El equipo necesita hacer cambios atómicos que cruzan boundaries
  • Quieres una sola fuente de verdad para configuración (linting, testing, CI)
  • Los proyectos tienen ciclos de release coordinados

Evitar cuando:

  • Proyectos completamente independientes sin código compartido
  • Equipos con ciclos de release muy diferentes
  • Restricciones de acceso estrictas (el monorepo implica visibilidad compartida)
  • El repo crecería a tamaños que Git no maneja bien (>10GB, millones de archivos)

Herramientas principales

HerramientaEnfoqueLenguajeCaracterísticas clave
TurborepoBuild cachingJS/TSCaché remoto, pipelines declarativos, zero-config
NxFull-featuredJS/TSGenerators, affected commands, graph visualization
pnpm workspacesPackage managerJS/TSSymlinks eficientes, strict dependencies
LernaPublishingJS/TSVersioning coordinado, changelogs (ahora parte de Nx)
BazelHermetic buildsPolíglotaReproducibilidad, escalabilidad extrema (Google-scale)
PantsHermetic buildsPython/Go/JavaSimilar a Bazel, mejor DX
RushEnterpriseJS/TSPolíticas estrictas, phantom dependencies detection

Turborepo vs Nx

La comparación más común en el ecosistema JavaScript:

Turborepo — minimalista, se integra con tu setup existente, excelente caché remoto con Vercel. Ideal si ya tienes un monorepo y quieres acelerar builds sin cambiar mucho.

Nx — más opinionado, incluye generators para scaffolding, plugins para frameworks específicos, visualización de dependencias. Mejor si empiezas de cero o quieres estructura guiada.

Estructura típica

monorepo/
├── apps/
│   ├── web/          # Next.js app
│   ├── mobile/       # React Native app
│   └── api/          # Backend service
├── packages/
│   ├── ui/           # Shared components
│   ├── utils/        # Shared utilities
│   └── config/       # Shared ESLint, TS configs
├── turbo.json        # Pipeline configuration
├── pnpm-workspace.yaml
└── package.json

Patrones clave

1. Internal packages

Paquetes que nunca se publican a npm — solo se consumen dentro del monorepo:

{
  "name": "@repo/ui",
  "private": true,
  "exports": {
    ".": "./src/index.ts"
  }
}

2. Task pipelines

Definir dependencias entre tareas para paralelización correcta:

{
  "pipeline": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": ["dist/**"]
    },
    "test": {
      "dependsOn": ["build"]
    }
  }
}

3. Caché remoto

El build de un paquete que no cambió se recupera del caché en lugar de re-ejecutarse:

# Primera vez: ejecuta build
turbo build  # 45s
 
# Segunda vez (sin cambios): recupera del caché
turbo build  # 0.3s

Anti-patrones

  • Monolito disfrazado — todo en un repo pero sin boundaries claros entre paquetes
  • Caché sin invalidación correcta — builds que no detectan cambios en dependencias
  • Circular dependencies — paquete A importa B que importa A
  • God package — un @repo/utils que crece sin control y todos dependen de él

Este sitio es un monorepo

jonmatum.com usa Turborepo + pnpm workspaces con apps/web (Next.js) y packages/knowledge (pipeline de contenido). El caché de Turborepo reduce el build de ~45s a menos de 1s cuando solo cambia contenido MDX.

¿Por qué importa?

La decisión entre monorepo y polyrepo afecta la velocidad de desarrollo, la complejidad del CI/CD y la capacidad de compartir código entre equipos. No hay respuesta universal — pero entender los trade-offs evita meses de migración dolorosa cuando la elección inicial no escala.

Referencias

Conceptos