Google e Meta mantêm monorepos internos há mais de dez anos, com time de infraestrutura de build que nenhuma empresa média replica. Turborepo, Nx e pnpm workspaces aproximaram a prática de times de dez pessoas. O resultado aparece quando o monorepo resolve um problema que o time já tem hoje.

Três problemas justificam a troca: código que mais de um projeto importa, mudança de API que precisa atravessar pacotes no mesmo deploy, e CI que roda tudo do zero a cada push.

O que monorepo resolve

Importar código sem publicar pacote

Design system, utilitários, tipos compartilhados e configuração de lint vivem num pacote do workspace e entram por import direto. O time para de coordenar versão publicada entre repositórios.

// em qualquer pacote do workspace
import { Button } from '@empresa/ui'
import { formatDate } from '@empresa/utils'
import type { User } from '@empresa/types'

Refatoração que atravessa projetos

Mudou a assinatura de uma função compartilhada? Você atualiza a função e os consumidores no mesmo commit. O monorepo elimina a janela em que dois repositórios rodam versões diferentes da mesma API. O livro Software Engineering at Google descreve como a empresa opera esse modelo na escala dela, com build system próprio incluído.

CI que só paga o diff

Turborepo e Nx leem o grafo de dependências e rodam build e teste apenas nos pacotes tocados pelo diff. O guia de caching do Turborepo documenta a chave de hash por pacote e o cache remoto, que leva o ganho para o CI da nuvem.

# build e test apenas nos pacotes afetados pelo diff
turbo run build test --filter='...[HEAD^1]'

O que monorepo não resolve

Monorepo não corrige código ruim. Dois projetos com arquiteturas conflitantes seguem conflitantes na mesma árvore de diretórios, e o conflito aparece no mesmo pull request. Monorepo também não substitui convenção de time. Sem regra compartilhada de lint, formatação e estrutura de pastas, você cria acoplamento entre times que discordam entre si.

Quando pular o monorepo

  • O time tem um ou dois projetos e nenhum código compartilhado entre eles.
  • Cada projeto tem ciclo de deploy próprio e domínio sem sobreposição.
  • Ninguém no time operou Nx ou Turborepo antes, e o prazo do trimestre não comporta a curva de aprendizado.
  • O produto muda de direção toda semana; velocidade de cada projeto pesa mais que consistência entre eles.

Turborepo ou Nx

Turborepo

Time de JavaScript e TypeScript que quer cache e pipeline incremental com pouca configuração. A referência de configuração cabe em poucas dezenas de linhas, e a integração com Vercel é nativa.

// turbo.json
{
  "tasks": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": [".next/**", "dist/**"]
    },
    "test": { "dependsOn": ["build"] },
    "dev": { "cache": false, "persistent": true }
  }
}

Nx

Monorepo maior, com mais de uma linguagem, ou time que quer gerador de código, visualização de grafo e plugins de framework. O modelo mental do Nx explica cache por operação e invalidação por hash de entrada. Mais poder, mais configuração para manter.

# gera aplicação React no monorepo
nx generate @nx/react:application my-app

# abre o grafo de dependências no browser
nx graph

Estrutura que eu uso para revisar PR

my-monorepo/
├── apps/
│   ├── web/           # Next.js
│   ├── mobile/        # React Native
│   └── api/           # Node.js
├── packages/
│   ├── ui/            # design system
│   ├── config/        # ESLint, TypeScript compartilhados
│   ├── utils/
│   └── types/
├── turbo.json
├── pnpm-workspace.yaml
└── package.json

A regra que eu aplico em revisão: apps/ guarda o que sobe para deploy, packages/ guarda o que é importado. Pacote não importa de app. App importa de qualquer pacote. O documento de workspaces do pnpm mostra o pnpm-workspace.yaml que amarra a árvore.

A decisão

Monorepo entra no plano quando você já tem, ou está a um trimestre de ter, múltiplos projetos com código compartilhado, times que trabalham em mais de um projeto, e mudança que precisa quebrar API entre pacotes no mesmo deploy. Monorepo fica de fora quando nenhum desses três pontos aparece na retrospectiva dos últimos três meses.

Adotar monorepo porque uma empresa grande usa o modelo importa pouco para a sua realidade: o modelo dela inclui um time de infraestrutura de build que você não tem. A decisão vale pelo problema de hoje. Polyrepo atende bem a maioria dos times até esse problema aparecer.