Advanced (Atualizado: 01/06/2026)

Gerenciar monorepos com Claude Code: pnpm, Turborepo, Nx e CI

Guia prático para monorepos com Claude Code: mapa do repositório, pnpm workspace, affected tasks, CODEOWNERS e CI.

Gerenciar monorepos com Claude Code: pnpm, Turborepo, Nx e CI

Um monorepo é um repositório Git que gerencia várias aplicações e bibliotecas no mesmo lugar. Ele facilita o compartilhamento de tipos, componentes UI, configuração e checks de CI. O problema aparece quando os limites não estão claros: uma alteração em packages/shared pode afetar apps/web, apps/api e vários pacotes sem que o PR deixe isso evidente.

O fluxo seguro é: pedir ao Claude Code um mapa do repositório, definir package boundaries, usar pnpm workspace com workspace:*, e executar apenas tarefas afetadas com Turborepo ou Nx. Como base oficial, consulte Nx Why Monorepos, Nx affected, Nx mental model, pnpm e Turborepo docs.

Estrutura desejada

Antes de editar, faça o Claude Code entender a arquitetura.

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/* são aplicações implantáveis. packages/* são blocos reutilizáveis. Package boundary é a regra que define quais pacotes podem depender de quais outros pacotes.

Primeiro prompt para Claude Code

Analise este repositório como um monorepo.

Premissas:
- apps/web é a aplicação Next.js
- apps/api é o servidor API
- packages/ui contém UI reutilizável
- packages/shared contém tipos, validações e funções puras
- packages/config contém ESLint, TypeScript, Prettier e configuração de testes

Regras:
- apps/* não deve depender diretamente de apps/*
- packages/* não deve depender de apps/*
- pacotes internos usam workspace:*
- após alterações, lint/test/build rodam como affected tasks

Primeiro gere um mapa do repo: dependências, ciclos perigosos, arquivos compartilhados demais e comandos de CI.
Ainda não edite arquivos.

Essa última linha evita mudanças cedo demais. Em monorepos, o risco principal costuma ser a direção da dependência.

pnpm workspace

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

No package.json raiz, mantenha comandos padronizados.

{
  "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"
  }
}

Dependências internas devem usar workspace:*.

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

Prompt recomendado:

Faça apps/web usar @acme/ui e @acme/shared.
Use workspace:* no package.json.
Não crie imports via ../../packages.
A alteração deve ser verificável com pnpm check:deps e pnpm ci:affected.

Turborepo e Nx affected

Turborepo é uma boa opção quando os pacotes já têm 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 ajuda quando o time precisa de project graph e affected mais detalhados.

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

Para Claude Code, peça “rode os checks afetados” em vez de “rode tudo”. Isso mantém CI rápido e barato.

CODEOWNERS e política de dependência

/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

Valide a política com código. Salve 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 é necessário porque os checks affected dependem do histórico Git.

Casos de uso práticos

  1. Alterar um Button em packages/ui. Claude Code deve manter a API pública estável e listar telas afetadas em apps/web.

  2. Mover DTOs compartilhados para packages/shared. DTO é o formato de dados entre API e UI, não o modelo do banco de dados.

  3. Atualizar TypeScript, Next.js ou ferramentas de teste. Comece por packages/config e depois verifique apenas apps afetadas.

  4. Implementar recursos transversais como pagamento ou busca. Peça ao Claude Code para dividir em PRs menores.

Armadilhas comuns

Primeiro, transformar packages/shared em uma gaveta de tudo. Ele deve conter código estável, genérico e fácil de testar.

Segundo, usar imports relativos como ../../packages/shared/src. Eles burlam a fronteira do pacote.

Terceiro, introduzir Turborepo e Nx profundamente ao mesmo tempo. Escolha um modelo principal antes.

Quarto, aceitar “funciona localmente” como prova. O PR precisa listar pacotes alterados, apps afetadas, comandos executados e riscos restantes.

Prompt de revisão

Revise este diff com foco em monorepo.

Verifique:
- não há dependência direta de apps/* para apps/*
- packages/* não depende de apps/*
- dependências internas usam workspace:*
- packages/shared contém apenas código compartilhado estável
- affected lint/test/build cobre a mudança
- CODEOWNERS deixa claro quem revisa

Retorne:
- bloqueadores
- correções recomendadas
- comandos verificados
- resumo de impacto para o PR

Continue com Claude Code e Nx workspace, Claude Code e pnpm workspace, Claude Code com Turborepo e colaboração em equipe com Claude Code.

Se sua equipe quer adotar Claude Code em um monorepo real, o essencial é definir limites, owners, CI e prompts de revisão. A consultoria e treinamento Claude Code da ClaudeCodeLab pode ajudar a desenhar isso no repositório real.

Resumo

Claude Code funciona bem em monorepos quando as restrições são explícitas. Repo map, package boundaries, pnpm workspace, Turborepo/Nx affected tasks, CODEOWNERS, política de dependências e checklist de CI transformam um patch isolado em um fluxo repetível. Na prática, impor workspace:* e padronizar pnpm ci:affected reduz falhas de revisão e CI desnecessário.

#Claude Code #monorepo #pnpm workspace #Turborepo #Nx
Grátis

PDF grátis: cheatsheet do Claude Code

Informe seu e-mail e baixe uma página com comandos, hábitos de revisão e workflows seguros.

Cuidamos dos seus dados e não enviamos spam.

Masa

Sobre o autor

Masa

Engenheiro focado em workflows práticos com Claude Code.