Advanced (Actualizado: 1/6/2026)

Gestionar monorepos con Claude Code: pnpm, Turborepo, Nx y CI

Guía práctica para gestionar monorepos con Claude Code: mapa del repo, pnpm workspace, affected tasks, CODEOWNERS y CI.

Gestionar monorepos con Claude Code: pnpm, Turborepo, Nx y CI

Un monorepo es un repositorio Git que gestiona varias aplicaciones y librerías en el mismo lugar. Permite compartir tipos, componentes UI, configuración y reglas de CI. El riesgo aparece cuando no hay límites claros: Claude Code puede hacer un cambio que parece pequeño en packages/shared y terminar afectando apps/web, apps/api y varios paquetes a la vez.

El flujo práctico es este: pedir primero un mapa del repositorio, definir package boundaries, usar pnpm workspace con workspace:*, y ejecutar solo las tareas afectadas con Turborepo o Nx. Para alinear conceptos, usa las guías oficiales de Nx sobre monorepos, Nx affected, Nx mental model, pnpm y Turborepo.

Estructura objetivo

Antes de editar, Claude Code debe entender la arquitectura.

graph TD
  WEB["apps/web"] --> UI["packages/ui"]
  WEB --> SHARED["packages/shared"]
  API["apps/api"] --> SHARED
  UI --> CONFIG["packages/config"]
  SHARED --> CONFIG
  CI["CI affected tasks"] --> WEB
  CI --> API

apps/* son aplicaciones desplegables. packages/* son piezas reutilizables. Una package boundary define qué paquete puede depender de otro. Es mejor darle esas reglas a Claude Code de forma explícita.

Primer prompt para Claude Code

Analiza este repositorio como monorepo.

Supuestos:
- apps/web es la app Next.js
- apps/api es el servidor API
- packages/ui contiene UI reutilizable
- packages/shared contiene tipos, validaciones y funciones puras
- packages/config contiene ESLint, TypeScript, Prettier y configuración de tests

Reglas:
- apps/* no debe depender directamente de apps/*
- packages/* no debe depender de apps/*
- los paquetes internos usan workspace:*
- después de editar, lint/test/build deben correr como affected tasks

Primero genera un mapa del repo: dependencias, ciclos peligrosos, archivos demasiado compartidos y comandos de CI.
No edites archivos todavía.

Esa última línea evita que Claude Code empiece a mover código antes de entender el sistema.

pnpm workspace

packages:
  - "apps/*"
  - "packages/*"

En el package.json raíz conviene exponer comandos estables.

{
  "name": "acme-monorepo",
  "private": true,
  "packageManager": "pnpm@10.12.1",
  "scripts": {
    "build": "turbo run build",
    "lint": "turbo run lint",
    "test": "turbo run test",
    "typecheck": "turbo run typecheck",
    "ci:affected": "turbo run lint test build --affected",
    "check:deps": "node scripts/check-workspace-deps.cjs"
  }
}

Las dependencias internas deben declararse así:

{
  "dependencies": {
    "@acme/shared": "workspace:*",
    "@acme/ui": "workspace:*"
  }
}

Prompt recomendado:

Haz que apps/web pueda usar @acme/ui y @acme/shared.
Usa workspace:* en package.json.
No uses imports con ../../packages.
La modificación debe poder verificarse con pnpm check:deps y pnpm ci:affected.

Turborepo y Nx affected

Turborepo funciona muy bien cuando cada paquete ya tiene scripts.

{
  "$schema": "https://turbo.build/schema.json",
  "tasks": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": ["dist/**", ".next/**", "!.next/cache/**"]
    },
    "lint": {
      "dependsOn": ["^build"]
    },
    "test": {
      "dependsOn": ["^build"],
      "outputs": ["coverage/**"]
    },
    "typecheck": {
      "dependsOn": ["^build"]
    },
    "dev": {
      "cache": false,
      "persistent": true
    }
  }
}

Nx aporta un project graph más fuerte y una lógica affected más rica.

pnpm dlx nx@latest init
pnpm nx affected -t lint test build --base=origin/main --head=HEAD

La instrucción correcta para Claude Code no es “ejecuta todo”, sino “ejecuta los checks afectados por este diff”.

CODEOWNERS y política de dependencias

/apps/web/ @acme/frontend
/apps/api/ @acme/backend
/packages/ui/ @acme/design-system
/packages/shared/ @acme/platform
/packages/config/ @acme/platform
/pnpm-workspace.yaml @acme/platform
/turbo.json @acme/platform

La política también debe validarse con código. Guarda esto como scripts/check-workspace-deps.cjs.

const fs = require("node:fs");
const path = require("node:path");

const ROOT = process.cwd();
const WORKSPACE_DIRS = ["apps", "packages"];
const DEP_FIELDS = ["dependencies", "devDependencies", "peerDependencies", "optionalDependencies"];

function readJson(file) {
  return JSON.parse(fs.readFileSync(file, "utf8"));
}

function findPackageDirs(baseDir) {
  const absoluteBase = path.join(ROOT, baseDir);
  if (!fs.existsSync(absoluteBase)) return [];
  return fs
    .readdirSync(absoluteBase, { withFileTypes: true })
    .filter((entry) => entry.isDirectory())
    .map((entry) => path.join(absoluteBase, entry.name))
    .filter((dir) => fs.existsSync(path.join(dir, "package.json")));
}

const packages = WORKSPACE_DIRS.flatMap(findPackageDirs).map((dir) => {
  const manifest = readJson(path.join(dir, "package.json"));
  return { dir, name: manifest.name, manifest };
});

const byName = new Map(packages.map((pkg) => [pkg.name, pkg]));
let failed = false;

for (const pkg of packages) {
  for (const field of DEP_FIELDS) {
    const deps = pkg.manifest[field] || {};
    for (const [name, range] of Object.entries(deps)) {
      const internal = byName.get(name);
      if (!internal) continue;
      const fromDir = path.relative(ROOT, pkg.dir).replace(/\\/g, "/");
      const toDir = path.relative(ROOT, internal.dir).replace(/\\/g, "/");

      if (!String(range).startsWith("workspace:")) {
        console.error(`${pkg.name}: ${name} must use workspace:* in ${field}`);
        failed = true;
      }
      if (toDir.startsWith("apps/")) {
        console.error(`${pkg.name}: ${fromDir} must not depend on app package ${toDir}`);
        failed = true;
      }
    }
  }
}

if (failed) process.exit(1);
console.log(`Checked ${packages.length} workspace packages.`);

Checklist de CI

name: monorepo-ci

on:
  pull_request:
  push:
    branches: [main]

jobs:
  checks:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - uses: pnpm/action-setup@v4
        with:
          version: 10
      - uses: actions/setup-node@v4
        with:
          node-version: 22
          cache: pnpm
      - run: pnpm install --frozen-lockfile
      - run: pnpm check:deps
      - run: pnpm ci:affected

fetch-depth: 0 es importante porque los checks affected necesitan historial Git suficiente.

Casos de uso

  1. Cambiar un Button en packages/ui. Claude Code debe mantener estable la API pública y listar las pantallas afectadas en apps/web.

  2. Mover DTO compartidos a packages/shared. Un DTO es la forma de datos entre API y UI; no es el modelo de base de datos.

  3. Actualizar TypeScript, Next.js o herramientas de test. Empieza por packages/config y verifica solo las apps afectadas.

  4. Implementar funcionalidades transversales como pagos o búsqueda. Pide a Claude Code dividir el trabajo en PRs pequeños.

Errores comunes

Primero, convertir packages/shared en un cajón de sastre. Solo debe tener código estable, genérico y fácil de probar.

Segundo, usar imports relativos como ../../packages/shared/src. Funcionan al principio, pero rompen la frontera del paquete.

Tercero, introducir Turborepo y Nx profundamente al mismo tiempo. Elige un modelo principal y añade el otro solo si hace falta.

Cuarto, aceptar “funciona localmente” como prueba suficiente. El PR debe explicar paquetes modificados, apps afectadas, comandos ejecutados y riesgos pendientes.

Prompt de revisión

Revisa este diff desde la perspectiva de monorepo.

Comprueba:
- no hay dependencia directa de apps/* a apps/*
- packages/* no depende de apps/*
- las dependencias internas usan workspace:*
- packages/shared solo contiene código compartido estable
- affected lint/test/build cubre el cambio
- CODEOWNERS deja clara la responsabilidad de revisión

Devuelve:
- blockers
- correcciones recomendadas
- comandos verificados
- resumen de impacto para el PR

Para profundizar, lee Claude Code y Nx workspace, Claude Code y pnpm workspace, Claude Code con Turborepo y colaboración en equipo con Claude Code.

Si tu equipo quiere introducir Claude Code en un monorepo real, el trabajo importante es definir límites, owners, CI y prompts de revisión. ClaudeCodeLab puede ayudar con formación y consultoría de Claude Code usando tu propio repositorio como base.

Resumen

Claude Code funciona bien en monorepos cuando las restricciones son explícitas. Repo map, package boundaries, pnpm workspace, Turborepo/Nx affected tasks, CODEOWNERS, política de dependencias y checklist de CI convierten una salida de IA en un flujo repetible. En la práctica, imponer workspace:* y estandarizar pnpm ci:affected reduce revisiones incompletas y CI innecesario.

#Claude Code #monorepo #pnpm workspace #Turborepo #Nx
Gratis

PDF gratis: cheatsheet de Claude Code

Introduce tu email y descarga una hoja con comandos, hábitos de revisión y flujos seguros.

Cuidamos tus datos y no enviamos spam.

Masa

Sobre el autor

Masa

Ingeniero enfocado en workflows prácticos con Claude Code.