Voltar para o Blog

Monorepos com Nx e Turborepo: A Revolução em Projetos JavaScript 2025

Olá HaWkers, monorepos se tornaram o padrão para projetos JavaScript em escala. Google, Facebook, Microsoft - gigantes da tech gerenciam milhões de linhas de código em repositórios únicos. E agora, com Nx e Turborepo, essa arquitetura está acessível para todos.

Você ainda gerencia múltiplos repos desconectados? Está perdendo velocidade e consistência.

O Que São Monorepos (E Por Que Importam)

Monorepo é estratégia arquitetural onde múltiplos projetos vivem em um único repositório, compartilhando código, ferramentas e configurações.

Vantagens Decisivas:

Compartilhamento de Código Trivial: Não precisa publicar pacotes NPM internos. Imports diretos entre projetos.

Refatoração Atômica: Mude interface? Atualize todos usos em um único commit. Impossível em polyrepos.

Tooling Unificado: ESLint, TypeScript, Prettier - uma configuração para tudo.

Builds Inteligentes: Ferramentas como Nx e Turborepo sabem exatamente o que mudou e compilam apenas o necessário.

Visibilidade Total: Veja impacto de mudanças em todo ecossistema imediatamente.

// Estrutura típica de monorepo
{
  "apps": {
    "web": "Next.js app principal",
    "admin": "Dashboard administrativo",
    "mobile": "React Native app"
  },
  "packages": {
    "ui": "Biblioteca de componentes compartilhados",
    "utils": "Utilidades comuns",
    "api-client": "Cliente API tipado",
    "config": "Configurações compartilhadas"
  }
}
// Nx - Monorepo poderoso e extensível
// nx.json - Configuração do Nx

{
  "tasksRunnerOptions": {
    "default": {
      "runner": "nx/tasks-runners/default",
      "options": {
        // Caching distribuído - compartilhe entre time
        "cacheableOperations": ["build", "test", "lint"],
        "parallel": 3
      }
    }
  },
  "targetDefaults": {
    "build": {
      // Dependências automáticas
      "dependsOn": ["^build"],
      "inputs": [
        "production",
        "^production"
      ],
      "outputs": ["{projectRoot}/dist"]
    }
  }
}

// apps/web/project.json
{
  "name": "web",
  "targets": {
    "build": {
      "executor": "@nx/next:build",
      "options": {
        "outputPath": "dist/apps/web"
      }
    },
    "serve": {
      "executor": "@nx/next:server",
      "options": {
        "port": 3000
      }
    }
  },
  // Nx detecta dependências automaticamente
  "implicitDependencies": []
}

// Turborepo - Velocidade extrema
// turbo.json

{
  "$schema": "https://turbo.build/schema.json",
  "pipeline": {
    "build": {
      // Define quais outputs podem ser cacheados
      "outputs": ["dist/**", ".next/**"],
      // Depende de build dos pacotes usados
      "dependsOn": ["^build"],
      // Variáveis de ambiente afetam cache
      "env": ["NODE_ENV"]
    },
    "test": {
      "dependsOn": ["build"],
      "outputs": ["coverage/**"],
      // Testes podem rodar em paralelo
      "cache": true
    },
    "lint": {
      // Não depende de nada, roda em paralelo
      "cache": true
    },
    "dev": {
      // Dev não faz cache (estado mutável)
      "cache": false,
      "persistent": true
    }
  }
}

// package.json na raiz
{
  "name": "monorepo",
  "private": true,
  "workspaces": [
    "apps/*",
    "packages/*"
  ],
  "scripts": {
    // Nx commands
    "build": "nx run-many --target=build --all",
    "test": "nx run-many --target=test --all",
    "affected:build": "nx affected --target=build",

    // Turborepo commands
    "turbo:build": "turbo run build",
    "turbo:test": "turbo run test --parallel"
  },
  "devDependencies": {
    "nx": "^17.0.0",
    "turbo": "^1.10.0"
  }
}

// Exemplo prático: Biblioteca compartilhada
// packages/ui/src/Button.tsx

export interface ButtonProps {
  variant: 'primary' | 'secondary';
  children: React.ReactNode;
  onClick?: () => void;
}

export function Button({ variant, children, onClick }: ButtonProps) {
  return (
    <button
      className={`btn btn-${variant}`}
      onClick={onClick}
    >
      {children}
    </button>
  );
}

// packages/ui/package.json
{
  "name": "@monorepo/ui",
  "version": "1.0.0",
  "main": "./src/index.ts",
  "types": "./src/index.ts"
}

// apps/web usa a biblioteca
// apps/web/pages/index.tsx

// Import direto - não precisa npm install!
import { Button } from '@monorepo/ui';

export default function Home() {
  return (
    <div>
      <h1>Welcome</h1>
      {/* TypeScript funciona perfeitamente */}
      <Button variant="primary" onClick={() => alert('Clicked!')}>
        Get Started
      </Button>
    </div>
  );
}

// Mudança na biblioteca reflete imediatamente
// Nx/Turborepo rebuildam apenas o necessário

// Exemplo de affected builds (Nx)
// Apenas projetos afetados por mudanças são recompilados

// Comando: nx affected:build --base=main
// Nx analisa git diff e compila apenas:
// - Projetos com arquivos modificados
// - Projetos que dependem dos modificados

// Caching inteligente
// Primeira build: 45 segundos
// Segunda build (sem mudanças): 0.1 segundos (cache)
// Build com mudança em 1 pacote: 5 segundos (apenas afetados)

Monorepo graph mostrando dependências

Nx vs Turborepo: Qual Escolher?

Nx: Poder e Flexibilidade

Pontos Fortes:

  • Ecosystem rico (plugins para React, Angular, Node, etc)
  • Dependency graph visualization
  • Code generators poderosos
  • Distributed task execution
  • Nx Cloud para cache remoto

Ideal Para:

  • Projetos enterprise complexos
  • Times que valorizam DX
  • Necessidade de customização profunda

Turborepo: Simplicidade e Velocidade

Pontos Fortes:

  • Configuração minimal
  • Performance extrema
  • Caching distribuído nativo
  • Integração perfeita com Vercel
  • Curva de aprendizado suave

Ideal Para:

  • Startups que precisam mover rápido
  • Projetos focados em web apps
  • Times que querem simplicidade

Padrões de Organização

Estrutura por Tipo

monorepo/
├── apps/           # Aplicações deployáveis
│   ├── web/
│   ├── api/
│   └── admin/
├── packages/       # Bibliotecas compartilhadas
│   ├── ui/
│   ├── utils/
│   └── config/
└── tools/          # Ferramentas de build

Estrutura por Domínio

monorepo/
├── domains/
│   ├── auth/
│   │   ├── app/
│   │   ├── api/
│   │   └── ui/
│   └── billing/
│       ├── app/
│       ├── api/
│       └── ui/
└── shared/
    ├── ui/
    └── utils/

Desafios e Soluções

Tempo de CI Aumentado

Desafio: CI precisa testar tudo, leva tempo.

Solução: Use affected commands. Teste apenas o que mudou. Nx/Turborepo detectam automaticamente.

Merge Conflicts

Desafio: Mais código = mais conflitos.

Solução: Estrutura bem organizada minimiza conflitos. Lock files são o maior problema - use yarn ou pnpm que lidam melhor.

Codebase Grande

Desafio: IDEs lentas com muitos arquivos.

Solução: Use TypeScript project references. IDEs modernos (VS Code) lidam bem com workspaces.

Se você trabalha com TypeScript em monorepos, leia: TypeScript em 2025: Por Que 38% dos Desenvolvedores Usam Diariamente.

Bora pra cima! 🦅

Comentários (0)

Esse artigo ainda não possui comentários 😢. Seja o primeiro! 🚀🦅

Adicionar comentário