Scaffolding de Projeto em 2026: Monorepo, Turborepo e Nx
Estruturar novos projetos em 2026 exige mais que `npm init`. Monorepos com Turborepo ou Nx oferecem shared configs, build caching e consistência em múltiplos pacotes.
Resumo executivo
Estruturar novos projetos em 2026 exige mais que `npm init`. Monorepos com Turborepo ou Nx oferecem shared configs, build caching e consistência em múltiplos pacotes.
Ultima atualizacao: 12/03/2026
Introdução: A evolução do scaffolding
Em 2026, npm init, create-react-app e vue-cli não são mais suficientes para projetos profissionais. Equipes exigem:
- Monorepo para shared configs (ESLint, Prettier, TypeScript)
- Build caching para desenvolvimento rápido (rebuilds em segundos, não minutos)
- Shared packages para reuso (UI components, utilities, types)
- CI/CD inteligente (apenas pacotes modificados são testados/deployed)
- Escalabilidade (adicionar novos pacotes deve ser trivial)
Monorepo tools como Turborepo e Nx emergiram como padrões para scaffolding de projeto moderno. Eles fornecem estrutura, convenção e automatização que transformam setup de projeto de tarefa repetitiva para processo eficiente e consistente.
O problema com scaffolding tradicional
Abordagem fragmentada
bash# Setup tradicional de projeto com múltiplos packages
# 1. Frontend
$ npx create-react-app frontend
# 2. Backend
$ npx express-generator backend
# 3. Shared
$ mkdir shared && cd shared
$ npm init -y
$ npm install typescript @types/node --save-dev
# 4. Manual config duplication
# Copia ESLint, Prettier, tsconfig entre todos os packages
# 5. Manual dependency management
# npm install em cada package, versões inconsistentes
# 6. Manual build scripts
# npm run build em cada package, sem paralelizaçãoProblemas:
- Config drift: ESLint, TypeScript configs divergem entre packages
- Inconsistent dependencies: React 18 em um package, 17 em outro
- Slow builds: Sem caching, tudo é rebuildado sempre
- Manual overhead: Adicionar novo package é processo manual complexo
- CI ineficiente: Todos packages são testados mesmo sem mudanças
Impacto em desenvolvimento
┌─────────────────────────────────────────────────────────────────────┐
│ SETUP TRADICIONAL │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ Developer: "Quero adicionar novo component compartilhado" │
│ │
│ 1. Cria pasta em shared/ │
│ 2. Configura tsconfig, Jest, ESLint manualmente │
│ 3. Adiciona package.json com scripts de build │
│ 4. Atualiza frontend/package.json com path │
│ 5. Atualiza backend/package.json com path │
│ 6. Roda npm install em cada package │
│ 7. Roda build manualmente para verificar │
│ │
│ Tempo: 2-3 horas de trabalho manual │
│ Chance de erro: Alta (esquecer atualizar algum package.json) │
│ │
└─────────────────────────────────────────────────────────────────────┘Turborepo: Simplicidade com performance
Conceitos fundamentais
Turborepo é ferramenta de monorepo focada em performance e simplicidade:
┌─────────────────────────────────────────────────────────────────────┐
│ TURBOREPO │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────┐ ┌──────────────┐ │
│ │ packages/ │ │ turbo.json │ │
│ │ │ │ │ │
│ │ - web/ │───────│ pipeline: │ │
│ │ - api/ │ │ web#build │ │
│ │ - shared/ │ │ dependsOn: │ │
│ │ - ui/ │ │ ["shared#build"] │ │
│ └─────────────┘ └──────────────┘ │
│ │ │
│ │ │
│ │ Turbo executa apenas mudanças │
│ │ com cache distribuído │
│ ▼ │
│ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ .turbo/cache/ │ │
│ │ (Cache local + remoto opcional) │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────┘Configuração inicial
bash# Cria monorepo com Turborepo
$ npx create-turbo@latest my-monorepo
# Estrutura gerada
my-monorepo/
├── apps/
│ ├── web/ # Frontend app
│ └── docs/ # Docs app
├── packages/
│ ├── ui/ # Componentes compartilhados
│ └── config/ # Configs compartilhadas
├── turbo.json # Config do Turborepo
└── package.json # Root package.json com workspacesjson// turbo.json
{
"$schema": "https://turbo.build/schema.json",
"globalDependencies": ["**/.env.*local"],
"pipeline": {
"build": {
"dependsOn": ["^build"],
"outputs": [".next/**", "!.next/cache/**", "dist/**"]
},
"test": {
"dependsOn": ["build"],
"outputs": ["coverage/**"]
},
"lint": {
"outputs": []
},
"dev": {
"cache": false,
"persistent": true
}
}
}json// package.json (root)
{
"name": "my-monorepo",
"private": true,
"workspaces": [
"apps/*",
"packages/*"
],
"scripts": {
"build": "turbo run build",
"dev": "turbo run dev",
"test": "turbo run test",
"lint": "turbo run lint"
},
"devDependencies": {
"turbo": "^2.0.0",
"eslint": "^8.0.0",
"prettier": "^3.0.0",
"typescript": "^5.0.0"
}
}Padrões de uso
bash# Desenvolve todos os apps e packages
$ npm run dev
# Build apenas packages que mudaram
$ npm run build
# Build package específico e dependências
$ turbo run build --filter=web
# Testa apenas packages que mudaram desde último commit
$ turbo run test --filter...[HEAD~1]
# Limpa cache local
$ turbo pruneIntegração CI/CD
yaml# .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
- name: Setup pnpm
uses: pnpm/action-setup@v2
with:
version: 8
- name: Get pnpm store directory
id: pnpm-cache
shell: bash
run: |
echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT
- name: Setup pnpm cache
uses: actions/cache@v3
with:
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
- name: Install dependencies
run: pnpm install
- name: Build affected apps
run: pnpm turbo run build --filter=...[origin/main]
- name: Test affected apps
run: pnpm turbo run test --filter=...[origin/main]Nx: Ecossistema completo de monorepo
Conceitos fundamentais
Nx oferece features mais avançadas que Turborepo, com foco em empresa:
┌─────────────────────────────────────────────────────────────────────┐
│ NX │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────┐ ┌──────────────┐ │
│ │ apps/ │ │ nx.json │ │
│ │ - web/ │───────│ generators: │ │
│ │ - api/ │ │ workspace: │ │
│ └─────────────┘ │ lib: │ │
│ │ │ @nx/react │ │
│ │ └──────────────┘ │
│ ┌─────────────┐ ┌──────────────┐ │
│ │ libs/ │ │ affected: │ │
│ │ - ui/ │ │ deps: │ │
│ │ - utils/ │───────│ apps │ │
│ └─────────────┘ └──────────────┘ │
│ │ │
│ │ Nx calcula grafo de dependências │
│ │ e executa em paralelo com cache │
│ ▼ │
│ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ nx/cache (remoto opcional) │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────┘Configuração inicial
bash# Cria monorepo com Nx
$ npx create-nx-workspace@latest my-nx-workspace
# Escolhe: Integrated Monorepo
# Escolhe: Stack (React, Next.js, NestJS, etc.)
# Escolhe: CI provider (GitHub Actions, GitLab, etc.)json// nx.json
{
"$schema": "./node_modules/nx/schemas/nx-schema.json",
"namedInputs": {
"default": ["{projectRoot}/**/*", "sharedGlobals"],
"production": [
"default",
"!{projectRoot}/**/?(*.spec|*.test).ts",
"!{projectRoot}/tsconfig.spec.json",
"!{projectRoot}/jest.config.ts",
"!{projectRoot}/src/test-setup.{ts,js}"
],
"sharedGlobals": []
},
"targetDefaults": {
"build": {
"cache": true,
"dependsOn": ["^build"],
"inputs": ["production", "^production"]
},
"test": {
"cache": true,
"inputs": ["default", "^production", "{workspaceRoot}/jest.preset.js"]
},
"lint": {
"cache": true,
"inputs": ["default", "{workspaceRoot}/.eslintrc.json"]
}
},
"plugins": [
"@nx/react",
"@nx/next",
"@nx/jest",
"@nx/eslint"
]
}Generators para scaffolding automático
Nx fornece generators para criar apps, libs e components automaticamente:
bash# Cria novo app Next.js
$ npx nx g @nx/next:app my-app --directory=apps/my-app
# Cria nova lib compartilhada
$ npx nx g @nx/react:lib my-lib --directory=libs/my-lib --importPath=@my-monorepo/my-lib
# Cria component em lib
$ npx nx g @nx/react:component Button --project=my-lib --export
# Cira novo NestJS service
$ npx nx g @nx/nest:service users --project=apiResultado:
- Configs (tsconfig, Jest, ESLint) criados automaticamente
- Dependencies adicionadas ao package.json correto
- Imports configurados com paths do tsconfig
- Scripts de build/test atualizados
Visualizador de grafo de dependências
bash# Visualiza grafo de dependências do projeto
$ npx nx graph
# Abre UI visual do Nx
$ npx nx show-project web --web┌─────────────────────────────────────────────────────────────────────┐
│ GRAFO DE DEPENDÊNCIAS NX │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────┐ │
│ │ web │ │
│ └─────┬────┘ │
│ │ │
│ ┌─────────┼─────────┐ │
│ ▼ ▼ ▼ │
│ ┌────────┐ ┌──────┐ ┌────────┐ │
│ │ ui │ │utils │ │config │ │
│ └────────┘ └──────┘ └────────┘ │
│ │ │
│ └─────────────┐ │
│ ▼ │
│ ┌──────────┐ │
│ │ api │ │
│ └──────────┘ │
│ │
│ Web depende de ui, utils, config │
│ API depende de utils, config │
│ Utils depende de config │
│ │
└─────────────────────────────────────────────────────────────────────┘pnpm Workspaces: Gerenciamento de dependências
Configuração de workspaces
json// package.json (root)
{
"name": "my-monorepo",
"private": true,
"scripts": {
"dev": "turbo run dev",
"build": "turbo run build"
},
"devDependencies": {
"turbo": "^2.0.0",
"typescript": "^5.0.0"
}
}yaml# pnpm-workspace.yaml
packages:
- 'apps/*'
- 'packages/*'bash# Instala dependências em todos os packages
$ pnpm install
# Adiciona dependência específica
$ pnpm add axios -w # Adiciona em workspace raiz
$ pnpm add axios -F web # Adiciona em workspace web
# Links workspaces localmente (no npm link)
$ pnpm install # Cria symlinks entre workspacesScripts de workspace
json// apps/web/package.json
{
"name": "web",
"scripts": {
"dev": "next dev",
"build": "next build",
"test": "jest"
},
"dependencies": {
"@my-monorepo/ui": "workspace:*", // Workspace local
"@my-monorepo/utils": "workspace:*",
"next": "^14.0.0",
"react": "^18.0.0"
}
}Padrões avançados de monorepo
1. Configs compartilhadas (ESLint, Prettier, TypeScript)
typescript// packages/config/eslint/index.ts
import { config } from '@my-monorepo/tsconfig';
export default [
{
ignores: ['node_modules', 'dist', '.next'],
extends: ['next/core-web-vitals', 'prettier'],
rules: {
'@typescript-eslint/no-unused-vars': 'error',
'react-hooks/rules-of-hooks': 'error',
// Regras compartilhadas
},
},
// Config custom por projeto quando necessário
config.eslintOverrides || {},
];typescript// apps/web/.eslintrc.js
module.exports = require('@my-monorepo/config/eslint');
// Usa config compartilhada, pode adicionar overrides específicos2. Types compartilhados
typescript// packages/types/src/index.ts
export interface User {
id: string;
email: string;
name: string;
}
export interface Product {
id: string;
name: string;
price: number;
}
export type ApiError = {
code: string;
message: string;
details?: unknown;
};typescript// apps/web/src/api/users.ts
import { User, ApiError } from '@my-monorepo/types';
async function getUser(id: string): Promise<User> {
const response = await fetch(`/api/users/${id}`);
if (!response.ok) {
throw await response.json() as ApiError;
}
return response.json();
}3. Shared utilities
typescript// packages/utils/src/date.ts
export function formatDate(date: Date): string {
return new Intl.DateTimeFormat('pt-BR', {
dateStyle: 'medium',
}).format(date);
}
export function parseDate(dateString: string): Date {
return new Date(dateString);
}
export function addDays(date: Date, days: number): Date {
const result = new Date(date);
result.setDate(result.getDate() + days);
return result;
}typescript// packages/utils/src/api.ts
import axios from 'axios';
export const api = axios.create({
baseURL: process.env.NEXT_PUBLIC_API_URL,
headers: {
'Content-Type': 'application/json',
},
});
export async function fetchWithError<T>(
url: string
): Promise<T> {
try {
const response = await api.get<T>(url);
return response.data;
} catch (error) {
if (axios.isAxiosError(error)) {
throw {
code: error.code,
message: error.message,
} as ApiError;
}
throw error;
}
}Comparando Turborepo vs Nx
Quando escolher Turborepo
Turbo é ideal quando:
- Você quer simplicidade e performance
- Seu time já conhece ferramentas padrão (Next.js, Jest, ESLint)
- Você não precisa de generators complexos
- Você prefere configuração manual sobre automatização
Vantagens:
- Setup rápido e simples
- Performance excelente
- Curva de aprendizado baixa
- Integração natural com frameworks modernos
Quando escolher Nx
Nx é ideal quando:
- Você tem time grande com múltiplos squads
- Você precisa de generators para consistência
- Você quer visualização de dependências
- Você precisa de integrações enterprise (Jira, Azure DevOps)
- Você quer automatizar patterns repetitivos
Vantagens:
- Generators poderosos para scaffolding
- Grafo de dependências visual
- Integrações com ferramentas enterprise
- Maior automização de workflows
Estratégias de migração
Migrando de repos separados para monorepo
bash# 1. Cria monorepo
$ npx create-turbo@latest my-monorepo
# 2. Move apps existentes
$ mv ../my-app apps/web
$ mv ../my-api apps/api
# 3. Cria estrutura de packages
$ mkdir -p packages/ui packages/utils packages/config
# 4. Extrai código compartilhado
$ # Move components para packages/ui
$ # Move utils para packages/utils
# 5. Atualiza imports
$ # Troca './components/Button' por '@my-monorepo/ui/Button'
# 6. Configura workspaces
$ # Atualiza package.json com workspaces
$ # Cria pnpm-workspace.yaml
# 7. Atualiza CI
$ # Configura turbo para build/test apenas afetadosMigrando de Turborepo para Nx (ou vice-versa)
A estrutura de packages/apps é compatível entre ambos:
bash# De Turborepo para Nx
$ npx add-nx-to-turbo-workspace
# Converte turbo.json para nx.json
# Adiciona generators Nx
# Atualiza scripts
# De Nx para Turborepo
$ npx @nx/workspace-to-turbo
# Converte nx.json para turbo.json
# Remove generators (Turbo não tem)
# Atualiza scriptsPlano de implementação em 60 dias
Semana 1-2: Seleção e setup
- Escolha entre Turborepo e Nx
- Cria monorepo inicial com scaffolding
- Configura CI/CD básico
Semana 3-4: Migração gradual
- Migrar um app existente
- Extrair código compartilhado para packages
- Atualizar imports e dependências
Semana 5-6: Otimização e automação
- Configurar cache remoto (Nx Cloud ou Turborepo Remote)
- Criar generators custom (se usando Nx)
- Documentar padrões de desenvolvimento
- Treinar equipe
Métricas de sucesso
- Build time: Build completo < 2 minutos (com cache)
- Dev startup:
npm run devinicia em < 10 segundos - Cache hit rate: > 80% de builds usam cache
- Time to new package: Adicionar novo package < 15 minutos
- CI time: CI/CD de PR < 5 minutos (build + test)
Sua equipe perde tempo com setups repetitivos e builds lentos? Fale com especialistas da Imperialis sobre scaffolding de projeto moderno, de monorepo a otimização de CI/CD, para transformar setup em produtividade.