Un monorepo migliora la condivisione del codice, il refactoring e la gestione delle dipendenze.
Turborepo: configurazione e struttura
Turborepo è ottimizzato per monorepo JavaScript/TypeScript.
# Create a new Turborepo monorepo
npx create-turbo@latest my-monorepo
cd my-monorepo
# Or add Turborepo to an existing monorepo
npm install turbo --save-dev
# Directory structure
my-monorepo/
├── apps/
│ ├── web/ # Next.js app
│ └── docs/ # Docs site
├── packages/
│ ├── ui/ # Shared React components
│ ├── utils/ # Shared utilities
│ └── tsconfig/ # Shared TypeScript configs
├── turbo.json # Pipeline configuration
└── package.json # Root workspace configConfigurazione pipeline Turborepo
Il pipeline turbo.json definisce come le attività si relazionano tra loro.
// turbo.json — pipeline definition
{
"$schema": "https://turbo.build/schema.json",
"pipeline": {
"build": {
"dependsOn": ["^build"], // ^ means: run in dependency order
"outputs": [".next/**", "!.next/cache/**", "dist/**"]
},
"test": {
"dependsOn": ["^build"],
"inputs": ["src/**/*.tsx", "src/**/*.ts", "test/**/*.ts"]
},
"lint": {
"outputs": []
},
"dev": {
"cache": false, // Never cache dev servers
"persistent": true // Long-running task
},
"type-check": {
"dependsOn": ["^build"],
"outputs": []
}
},
"globalEnv": ["NODE_ENV", "DATABASE_URL"]
}
# Run all build tasks (uses cache if inputs unchanged)
npx turbo build
# Run only for specific apps/packages
npx turbo build --filter=web
npx turbo build --filter=...ui # ui and all its dependents
# Force re-run (bypass cache)
npx turbo build --force
# View task graph
npx turbo build --graphNx: configurazione e grafico del progetto
Nx offre un set di funzionalità più ricco.
# Create Nx monorepo
npx create-nx-workspace@latest my-nx-repo --preset=ts
# Add Nx to existing monorepo
npx nx@latest init
# Generate a new app or library
nx generate @nx/next:app web
nx generate @nx/react:library ui
nx generate @nx/node:library utils
# nx.json — workspace configuration
{
"tasksRunnerOptions": {
"default": {
"runner": "nx/tasks-runners/default",
"options": {
"cacheableOperations": ["build", "test", "lint", "e2e"],
"parallel": 3
}
}
},
"targetDefaults": {
"build": {
"dependsOn": ["^build"],
"inputs": ["production", "^production"]
}
},
"namedInputs": {
"default": ["{projectRoot}/**/*", "sharedGlobals"],
"production": ["default", "!{projectRoot}/**/?(*.)+(spec|test).[jt]s?(x)"],
"sharedGlobals": []
}
}pnpm Workspaces: approccio leggero
pnpm workspaces fornisce supporto nativo per monorepo senza strumenti aggiuntivi.
# pnpm-workspace.yaml
packages:
- 'apps/*'
- 'packages/*'
# Install all workspace dependencies
pnpm install
# Add a package to a specific workspace
pnpm add react --filter @myapp/web
# Add a local workspace package as dependency
# In apps/web/package.json:
{
"dependencies": {
"@myapp/ui": "workspace:*"
}
}
# Run scripts across all packages
pnpm --filter '*' run build
pnpm --filter './apps/*' run dev
pnpm --filter '...@myapp/ui' run test # ui and dependents
# Publish all public packages
pnpm publish -r --access publicCache remota
La cache remota condivide gli artefatti di build tra sviluppatori e CI.
# Turborepo Remote Cache (Vercel)
# Enables sharing build cache across developers and CI
# 1. Link to Vercel
npx turbo login
npx turbo link
# 2. Now CI builds share cache with local dev:
# CI run: builds from scratch, uploads to cache
# Developer: pulls cache, gets instant builds
# Self-host with Turborepo Remote Cache (open source)
# docker run -p 3000:3000 ducktors/turborepo-remote-cache
# .turbo/config.json (auto-generated by turbo link)
{
"teamId": "team_xxx",
"apiUrl": "https://vercel.com"
}
# Nx Cloud (similar offering from Nx)
# nx connect-to-nx-cloud
# Provides remote caching + task distributionVersioning con Changesets
Changesets è lo strumento standard per il versioning e la pubblicazione in monorepo.
# Changesets — versioning and publishing for monorepos
# Works with npm/yarn/pnpm workspaces
pnpm add -D @changesets/cli
pnpm changeset init
# When you make a change that needs a version bump:
pnpm changeset
# → Interactive prompt: which packages changed, bump type (major/minor/patch)
# Creates a markdown file in .changeset/ describing the change
# Example .changeset/funny-bears-dance.md:
---
"@myapp/ui": minor
"@myapp/utils": patch
---
Add new Button component with loading state
# Apply changesets (bumps versions, updates CHANGELOG.md)
pnpm changeset version
# Publish all changed packages
pnpm changeset publishTurborepo vs Nx vs pnpm Workspaces
| Feature | Turborepo | Nx | pnpm Workspaces |
|---|---|---|---|
| Setup complexity | Low | Medium | Very Low |
| Task caching | Built-in | Built-in | Manual/external |
| Remote cache | Vercel (free tier) | Nx Cloud (paid) | None built-in |
| Code generators | No | Yes (rich) | No |
| Affected detection | Basic (--filter) | Advanced (nx affected) | Via Changesets |
| Language support | JS/TS focused | Polyglot | Any |
| Learning curve | Low | Medium-High | Low |
Best practice
- Iniziare con pnpm workspaces + Turborepo.
- Definire confini chiari: pacchetti condivisi in packages/, app in apps/.
- Usare Changesets per il versioning.
- Abilitare la cache remota presto.
- Tenere esplicito il package.json di ogni pacchetto.
FAQ
Turborepo o Nx?
Turborepo è più semplice per la maggior parte dei progetti JS. Nx ha più funzionalità per grandi repo.
Monorepo vs polyrepo?
Un monorepo memorizza tutto il codice in un unico repository.
Come funziona il caching di Turborepo?
Turborepo fa l'hash degli input di ogni task e ripristina gli output dalla cache.
Diversi gestori di pacchetti nel monorepo?
No. Tutti i workspace devono usare lo stesso gestore di pacchetti.
Variabili d'ambiente nel monorepo?
Definire le variabili per app e elencarle in turbo.json globalEnv.