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.
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
-
Alterar um Button em
packages/ui. Claude Code deve manter a API pública estável e listar telas afetadas emapps/web. -
Mover DTOs compartilhados para
packages/shared. DTO é o formato de dados entre API e UI, não o modelo do banco de dados. -
Atualizar TypeScript, Next.js ou ferramentas de teste. Comece por
packages/confige depois verifique apenas apps afetadas. -
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.
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.
Sobre o autor
Masa
Engenheiro focado em workflows práticos com Claude Code.
Artigos relacionados
Permission receipt no Claude Code: escopo, prova e rollback
Padrão de permission receipt para Claude Code: ações permitidas, limites de aprovação, comandos de prova, rollback e CTA de receita.
Agent Harness seguro para Claude Code e Codex: permissoes, verificacao e rollback
Monte uma base segura para agentes com Claude Code e Codex usando politicas, plano, verificacao e recuperacao.
Subagentes no Claude Code: guia prático para delegar trabalho com segurança
Guia prático de subagentes no Claude Code para dividir artigos e código: regras, prompts, riscos e checklist.