Monorepo profissional: pnpm workspaces + Turbo + shared configs
⏱ 13 min·⭐ 55 XP
Pré-requisitos (0/1)0%
- ⬜🚀 Performance em Node: event loop, streams e backpressure(TypeScript Profissional)
Recomendamos completar os pré-requisitos antes de seguir, mas nada te impede de continuar.
Por que monorepo
| Dimensão | Repositório único | Vários repositórios |
|---|---|---|
| Mudança que cruza pacotes | Um commit, revisado junto | N pedidos coordenados à mão |
| Versão entre pacotes internos | Sempre a do repositório | Publicar e atualizar dependência a cada mudança |
| Esteira | Uma, com grafo de dependência | Uma por repositório, sem visão do todo |
| Tempo de construção | Cresce com o repositório — exige cache | Naturalmente isolado |
| Fronteira entre times | Precisa de convenção e de dono por pasta | Fronteira física, imposta pela ferramenta |
| Custo de entrada | Instalação única resolve tudo | Descobrir e clonar N repositórios |
DimensãoMudança que cruza pacotes
Repositório únicoUm commit, revisado junto
Vários repositóriosN pedidos coordenados à mão
DimensãoVersão entre pacotes internos
Repositório únicoSempre a do repositório
Vários repositóriosPublicar e atualizar dependência a cada mudança
DimensãoEsteira
Repositório únicoUma, com grafo de dependência
Vários repositóriosUma por repositório, sem visão do todo
DimensãoTempo de construção
Repositório únicoCresce com o repositório — exige cache
Vários repositóriosNaturalmente isolado
DimensãoFronteira entre times
Repositório únicoPrecisa de convenção e de dono por pasta
Vários repositóriosFronteira física, imposta pela ferramenta
DimensãoCusto de entrada
Repositório únicoInstalação única resolve tudo
Vários repositóriosDescobrir e clonar N repositórios
Empresas como Google, Meta, Microsoft — todas escolheram monorepo. Motivos:
- Atomic commits: mudança que afeta lib + app viram um commit só, revisado junto.
- Shared packages: UI lib, types, configs reusados sem publicar no npm.
- CI unificada: build/test de tudo num lugar.
- Refatoração cross-projeto: editor enxerga tudo.
💡
Monorepo ≠ gigante arquivo único. Cada package é isolado. O que é compartilhado é o repositório, não o código.
Estrutura típica
.
├── package.json # raiz, só devDeps
├── pnpm-workspace.yaml # define packages/*
├── turbo.json # pipeline
├── tsconfig.base.json # config shared
├── packages/
│ ├── ui/ # componentes
│ ├── utils/ # helpers puros
│ └── types/ # tipos shared
└── apps/
├── web/ # Next.js
└── api/ # backend🗺️ A anatomia de um monorepo pnpm + Turborepo
raiz/ (pnpm-workspace.yaml + turbo.json)— Define QUAIS pastas são workspaces e como as tasks (build, test, lint) se encadeiam entre elas.
apps/ — o que roda em produção— web, api, worker — cada um um pacote com seu próprio package.json, consumindo os pacotes de packages/.
packages/ — código compartilhado— ui, config, types — nunca rodam sozinhos; existem para serem importados por apps/.
tsconfig.base.json compartilhado— Cada pacote estende a base — muda em um lugar, vale para todos.
pnpm-workspace.yaml + turbo.json
# pnpm-workspace.yaml
packages:
- 'packages/*'
- 'apps/*'{
"pipeline": {
"build": {
"dependsOn": ["^build"],
"outputs": ["dist/**", ".next/**"]
},
"test": {
"dependsOn": ["build"],
"outputs": []
},
"lint": { "outputs": [] },
"dev": { "cache": false, "persistent": true }
}
}^build = "primeiro build dos packages dos quais eu dependo". outputs diz o que cachear. Turbo hasheia inputs; se nada mudou, reusa.
Quiz rápido
Seu código importa um pacote que não está no `package.json` daquele workspace, e o pnpm quebra o build. Como interpretar isso?
Armadilhas reais
- Hoisting sujeito a bug: pnpm é strict. Se seu código importa lib não declarada (veio transiente), quebra. Isso é FEATURE — declare no package.json.
- Peer deps entre workspaces: especifique como — pnpm resolve pro package local automaticamente.
- CI cold: sem remote cache, builds de monorepo grande ficam lentos. Turbo remote cache (ou self-hosted) resolve.
- VSCode perdido: abra o monorepo pela raiz, não por subfolder — senão Intellisense não enxerga packages irmãos.
Perguntas frequentes
❓ Quando um repositório único compensa?
Quando há código compartilhado entre projetos e mudança atômica entre eles é frequente — alterar o pacote comum e os consumidores no mesmo pedido. Com projetos independentes, ele acrescenta ferramenta e não devolve nada.
❓ Qual o maior problema de repositório único?
Tempo de verificação: rodar tudo a cada mudança fica insustentável. A solução é execução por afetados com cache de resultado, e é justamente para isso que as ferramentas de orquestração existem. Sem elas, o repositório único vira gargalo.
❓ Como versionar pacotes internos?
Por referência de workspace durante o desenvolvimento e versão publicada quando o pacote sai para fora. Misturar os dois modelos é o que gera o caso de o consumidor apontar para versão publicada antiga enquanto o autor testa a local.
Fixando
Quiz rápido
O que `"dependsOn": ["^build"]` expressa na configuração do pipeline?
Quiz rápido
Qual armadilha aparece ao abrir o monorepo pela subpasta de um pacote no editor?
Terminou de ler?
Marcar como concluído registra o XP, mantém sua sequência e coloca 3 cartas deste módulo na fila de revisão espaçada.
Próximos passos sugeridos
Temas deste módulo
Discussão
Carregando comentários…