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": "[email protected]",
"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
Crie um log de orçamento Claude Code antes do custo ficar confuso
Registre quem usou Claude Code, para qual trabalho e qual resultado gerou no time.
Checagem de 3 minutos antes do commit: confira o que o Claude Code mexeu antes de fechar
Roteiro de 3 minutos para flagrar antes do commit as mudanças que o Claude Code ampliou sozinho: escopo, diff e quais arquivos stagear.
Registro de riscos: o que montar antes de levar Claude Code para a equipe
Como montar um registro de riscos para levar Claude Code à equipe sem acidentes de permissão, CI e deploy. Com exemplos e código.