O que é Turborepo?
Turborepo é um sistema de build de alta performance para monorepos JavaScript. Ele executa tarefas em todos os pacotes do seu repositório, respeita a ordem de dependência entre eles e armazena os resultados em cache para que o trabalho não alterado nunca seja repetido.
Um monorepo sem um sistema de build rapidamente se torna problemático. Executar build e test manualmente em cada pacote é lento, e um script simples reexecuta tudo mesmo quando apenas um pacote foi alterado. O Turborepo resolve ambos os problemas: um pipeline de tarefas declarativo cuida da ordenação, e o hashing baseado em conteúdo torna as tarefas não alteradas efetivamente gratuitas.
O pipeline de tarefas
O pipeline fica em turbo.json. Cada tarefa declara suas dependências e outputs.
{
"$schema": "https://turbo.build/schema.json",
"tasks": {
"build": {
"dependsOn": ["^build"],
"outputs": ["dist/**", ".next/**"]
},
"test": {
"dependsOn": ["build"],
"outputs": ["coverage/**"]
},
"lint": {},
"dev": {
"cache": false,
"persistent": true
}
}
}
dependsOn com um circunflexo (^build) significa “construa minhas dependências primeiro”. Sem o circunflexo, refere-se a uma tarefa no mesmo pacote. outputs informa ao Turborepo o que deve ser colocado em cache, e cache: false remove tarefas como dev do cache porque elas são executadas indefinidamente.
Executando tarefas
Um único comando executa uma tarefa em todo o repositório, na ordem correta e em paralelo sempre que possível.
turbo run build
turbo run test lint
turbo run dev --filter=web
O Turborepo constrói um grafo a partir de dependsOn, executa tarefas independentes simultaneamente e enfileira aquelas que possuem dependências. O resultado é o cronograma mais rápido possível que ainda respeita as restrições entre os pacotes.
Caching
O caching é o recurso que muda completamente a experiência de usar um monorepo. Para cada tarefa, o Turborepo gera um hash dos inputs — arquivos de origem, dependências, variáveis de ambiente e configuração — e armazena os outputs e logs vinculados a esse hash.
Na próxima execução, se o hash não tiver sido alterado, a tarefa é ignorada e seus outputs são restaurados do cache. Os logs também são reproduzidos, então o output parece o mesmo, mas sem que o trabalho precise ser refeito. Com um cache “quente”, um turbo run build completo em dezenas de pacotes pode ser finalizado em segundos.
Cache remoto
Um cache local ajuda apenas uma máquina. O cache remoto compartilha o cache entre a equipe e a CI.
- Um desenvolvedor faz o build de um pacote; o resultado é enviado (upload).
- Outro desenvolvedor faz o checkout do mesmo commit e o restaura instantaneamente.
- A CI restaura os mesmos artefatos, pulando o trabalho que já foi realizado em outro lugar.
Isso transforma o cache em um ativo compartilhado e é, frequentemente, o maior ganho de velocidade de CI para um monorepo. A Vercel oferece um cache remoto hospedado, e existem opções self-hosted para equipes que precisarem.
Filtragem
Monorepos grandes raramente precisam executar todas as tarefas. A filtragem permite focar em um subconjunto de pacotes.
# only packages affected by changes since main
turbo run test --filter="...[origin/main]"
# one package and its dependencies
turbo run build --filter=web...
# only packages that depend on @repo/ui
turbo run build --filter=...@repo/ui
A sintaxe [origin/main] solicita que o Turborepo calcule quais pacotes foram alterados e inclua seus dependentes. No CI, isso significa que um pull request que altere apenas um pacote irá buildar e testar apenas aquilo que ele realmente pode afetar.
Workspaces e estrutura
O Turborepo não gerencia dependências por conta própria — esse é o trabalho do gerenciador de pacotes. Você define os workspaces com pnpm, npm, yarn ou bun, e o Turborepo adiciona a camada de pipeline e cache por cima.
repo/
├── apps/
│ ├── web/ # a deployable app
│ └── docs/
├── packages/
│ ├── ui/ # a shared component library
│ └── config/ # shared config
├── package.json
├── pnpm-workspace.yaml
└── turbo.json
Os apps consomem pacotes compartilhados através do protocolo de workspace, e o Turborepo compreende esse grafo de dependências ao ordenar as tarefas. A combinação de pnpm workspaces para vinculação e Turborepo para a execução de tarefas é a configuração de monorepo moderna mais comum.
Melhores práticas
- Declare
outputspara cada tarefa que possa ser cacheada. - Use
dependsOncom^para expressar a ordem de dependência. - Marque tarefas de longa duração, como
dev, comcache: false. - Ative o remote caching no CI para obter os maiores ganhos.
- Filtre por pacotes alterados no CI para manter as pipelines rápidas.
- Mantenha o
turbo.jsonna raiz do repositório e compartilhe-o entre os pacotes. - Adicione um script na raiz para que toda a equipe execute os mesmos comandos.
Erros comuns
- Esquecer o
outputse perder o benefício do cache. - Executar tarefas em ordem arbitrária em vez de usar
dependsOn. - Fazer o cache de uma tarefa persistente, como um servidor de desenvolvimento.
- Incluir variáveis de ambiente voláteis no hash desnecessariamente.
- Executar o pipeline completo no CI quando a filtragem pularia os pacotes não afetados.
- Tratar o Turborepo como um substituto para um gerenciador de pacotes.
Próximos passos
O Turborepo transforma um monorepo de um fardo em uma vantagem. Combine-o com o pnpm para o linking de workspaces, entenda os fundamentos do npm e do Node.js, e mantenha a build de cada pacote individual com o Vite. Depois, adicione um turbo run build na raiz de um repositório com mais de um pacote e veja a segunda execução terminar quase instantaneamente.