Como configurar monorepo com Turborepo para projetos frontend
1. Introdução ao Monorepo e Turborepo
Um monorepo é uma estratégia de gerenciamento de código onde múltiplos projetos são armazenados em um único repositório. Para projetos frontend, essa abordagem oferece vantagens significativas: compartilhamento de código entre aplicações, padronização de configurações e visibilidade centralizada de dependências.
Turborepo é uma ferramenta moderna de build system para monorepos JavaScript/TypeScript que se destaca por três características principais:
- Cache inteligente: evita rebuilds desnecessários, reutilizando resultados anteriores
- Build paralelo: executa tarefas simultaneamente quando não há dependências entre pacotes
- Simplicidade: configuração mínima comparada a alternativas como Nx ou Lerna
Enquanto Yarn Workspaces ou pnpm Workspaces gerenciam apenas a instalação de dependências entre pacotes, o Turborepo adiciona orquestração de tarefas com cache e paralelismo.
2. Pré-requisitos e configuração inicial
Antes de começar, certifique-se de ter instalado:
- Node.js (versão 18 ou superior)
- pnpm (recomendado) ou yarn
- Git
Para iniciar um monorepo com Turborepo, execute:
npx create-turbo@latest meu-monorepo-frontend
cd meu-monorepo-frontend
O comando create-turbo gera uma estrutura inicial com dois apps (web e docs) e alguns packages compartilhados. Se preferir começar do zero, crie a estrutura manualmente:
mkdir meu-monorepo-frontend
cd meu-monorepo-frontend
pnpm init
pnpm add -D turbo
3. Estrutura de pacotes e workspaces
A estrutura recomendada para projetos frontend segue este padrão:
meu-monorepo-frontend/
├── apps/
│ ├── web/ # Aplicação Next.js
│ ├── admin/ # Dashboard React
│ └── mobile/ # React Native (opcional)
├── packages/
│ ├── ui/ # Componentes compartilhados
│ ├── utils/ # Funções utilitárias
│ ├── eslint-config # Configuração ESLint
│ └── tsconfig/ # Configuração TypeScript base
├── package.json
├── turbo.json
└── pnpm-workspace.yaml
Configure o workspace no pnpm-workspace.yaml:
packages:
- "apps/*"
- "packages/*"
No package.json raiz, adicione:
{
"private": true,
"scripts": {
"dev": "turbo run dev",
"build": "turbo run build",
"lint": "turbo run lint",
"test": "turbo run test"
},
"devDependencies": {
"turbo": "^2.0.0"
}
}
4. Configuração do Turborepo para build e cache
O coração da configuração está no turbo.json. Defina os pipelines de tarefas:
{
"$schema": "https://turbo.build/schema.json",
"globalDependencies": ["**/.env.*local"],
"pipeline": {
"build": {
"dependsOn": ["^build"],
"outputs": [".next/**", "dist/**"]
},
"dev": {
"cache": false,
"persistent": true
},
"lint": {
"dependsOn": ["^build"]
},
"test": {
"dependsOn": ["build"],
"inputs": ["src/**/*.tsx", "src/**/*.ts"]
}
}
}
Para ativar cache remoto (útil em times), configure com Vercel:
npx turbo login
npx turbo link
Comandos úteis para o dia a dia:
# Build de todos os pacotes
turbo run build
# Build apenas do app web
turbo run build --filter=web
# Desenvolvimento com escopo
turbo run dev --filter=web --filter=ui
5. Compartilhando código entre projetos frontend
Vamos criar um pacote de componentes UI reutilizável. Primeiro, configure packages/ui/package.json:
{
"name": "@meu-monorepo/ui",
"version": "0.1.0",
"main": "./src/index.ts",
"types": "./src/index.ts",
"scripts": {
"build": "tsc",
"dev": "tsc --watch"
},
"devDependencies": {
"typescript": "^5.0.0"
}
}
Crie um componente de botão em packages/ui/src/Button.tsx:
import React from 'react';
interface ButtonProps {
children: React.ReactNode;
variant?: 'primary' | 'secondary';
onClick?: () => void;
}
export const Button: React.FC<ButtonProps> = ({
children,
variant = 'primary',
onClick
}) => {
const baseStyles = 'px-4 py-2 rounded font-medium';
const variantStyles = {
primary: 'bg-blue-500 text-white hover:bg-blue-600',
secondary: 'bg-gray-200 text-gray-800 hover:bg-gray-300'
};
return (
<button
className={`${baseStyles} ${variantStyles[variant]}`}
onClick={onClick}
>
{children}
</button>
);
};
Configure TypeScript paths no tsconfig.json raiz:
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@meu-monorepo/ui": ["packages/ui/src"],
"@meu-monorepo/utils": ["packages/utils/src"]
}
}
}
Agora, no app Next.js (apps/web), adicione a dependência:
{
"dependencies": {
"@meu-monorepo/ui": "workspace:*"
}
}
E use o componente:
import { Button } from '@meu-monorepo/ui';
export default function Home() {
return (
<div>
<Button variant="primary" onClick={() => alert('Clicou!')}>
Meu Botão Compartilhado
</Button>
</div>
);
}
6. Gerenciamento de dependências e versionamento
Para instalar dependências globais (usadas por todos os pacotes):
pnpm add -D typescript -w
Para dependências específicas de um pacote:
pnpm add react --filter=web
Para versionamento, recomendo usar Changesets:
pnpm add -D @changesets/cli -w
npx changeset init
Configure o fluxo de versionamento:
# Criar changeset
npx changeset
# Versionar pacotes
npx changeset version
# Publicar
npx changeset publish
Para evitar conflitos de versão, mantenha dependências como React, TypeScript e ESLint na raiz do monorepo:
{
"devDependencies": {
"typescript": "^5.3.0",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"pnpm": {
"overrides": {
"react": "^18.2.0"
}
}
}
7. Integração contínua e boas práticas
Configure GitHub Actions para CI eficiente com Turborepo:
# .github/workflows/ci.yml
name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v2
with:
version: 8
- uses: actions/setup-node@v4
with:
node-version: 18
cache: 'pnpm'
- run: pnpm install
- run: pnpm turbo build --filter=[main]
- run: pnpm turbo lint --filter=[main]
- run: pnpm turbo test --filter=[main]
Use --since para executar apenas tarefas afetadas por mudanças:
turbo run build --since=main
turbo run test --filter=./packages/ui
Dicas de performance:
- Configure
.turbono.gitignore - Use
--concurrencypara controlar paralelismo - Defina
cache: falsepara tarefas que não devem ser cacheadas (comodev)
8. Próximos passos e considerações finais
Migrar projetos existentes para um monorepo com Turborepo pode ser feito gradualmente:
- Comece com um projeto pequeno como piloto
- Extraia componentes comuns para packages
- Adicione novos projetos ao workspace
Monitore o tamanho do repositório com ferramentas como turborepo-remote-cache e evite incluir node_modules no cache do Git.
O Turborepo é uma excelente escolha para equipes frontend que buscam produtividade sem complexidade excessiva. Sua integração com Vercel, o cache inteligente e a simplicidade de configuração o tornam ideal para projetos de médio a grande porte.
Referências
- Documentação oficial do Turborepo — Guia completo de configuração, pipelines e cache remoto
- Monorepo com Turborepo: Guia prático — Tutorial passo a passo com exemplos de React e Next.js
- pnpm Workspaces com Turborepo — Documentação oficial do pnpm sobre workspaces e integração com Turborepo
- Changesets: Versionamento semântico para monorepos — Ferramenta recomendada para gerenciar versões em monorepos
- GitHub Actions para Turborepo — Guia da Microsoft sobre CI/CD com Node.js e Turborepo
- Turborepo vs Nx vs Lerna — Comparativo detalhado entre as principais ferramentas de monorepo
- Cache remoto Turborepo com Vercel — Documentação oficial da Vercel sobre configuração de cache remoto