Turborepo is a build system optimized for JavaScript and TypeScript monorepos, written in Rust. It handles task orchestration, caching, and dependency management across multiple packages in a single repository.
Core Concepts
Monorepo Structure
my-monorepo/
├── apps/
│ ├── web/
│ ├── mobile/
│ └── admin/
├── packages/
│ ├── ui-library/
│ ├── utils/
│ └── types/
├── turbo.json (configuration)
├── package.json (root workspace)
└── pnpm-workspace.yaml (or package.json for npm/yarn workspaces)
Key Concepts
- Package Graph: Relationship between all packages in the monorepo
- Task Graph: Dependency relationships between tasks
- Caching: Turborepo remembers task outputs and reuses them when inputs haven't changed
- Remote Caching: Share cache artifacts across team members and CI/CD systems
Installation & Setup
Initialize a New Turborepo
npx create-turbo@latest
Add Turborepo to Existing Project
npm install turbo --save-dev
# Initialize configuration
turbo init
turbo.json Configuration
Basic Structure
{
"extends": ["//"],
"globalDependencies": ["*.env", "package.json"],
"globalEnv": ["NODE_ENV"],
"globalPassThroughEnv": ["HOME", "PATH"],
"pipeline": {
"build": {
"dependsOn": ["^build"],
"outputs": ["dist/**", ".next/**"],
"cache": true,
"env": ["NODE_ENV", "API_*"]
},
"test": {
"dependsOn": ["build"],
"outputs": ["coverage/**"],
"cache": true
},
"dev": {
"cache": false,
"persistent": true,
"interactive": true
},
"lint": {
"outputs": []
}
}
}
Task Definition Options
| Option | Description | Example |
|---|---|---|
dependsOn | Tasks that must complete first | ["^build"], ["build", "lint"] |
outputs | Files to cache | ["dist/**", ".next/**"] |
cache | Enable/disable caching | true or false |
env | Environment variables that affect hashing | ["NODE_ENV", "API_*"] |
passThroughEnv | Environment variables available but not cached | ["HOME"] |
inputs | Files to consider for cache invalidation | ["src/**", "package.json"] |
persistent | Mark as long-running (dev servers) | true |
interactive | Accept stdin input | true |
interruptible | Allow restart by turbo watch | true |
outputLogs | Log verbosity | "full", "hash-only", "new-only", "errors-only", "none" |
Dependency Prefix Symbols
| Symbol | Meaning | Example |
|---|---|---|
^ | Depends on same task in dependencies | "^build" (wait for deps to build) |
| No prefix | Same-package dependency | "build" (in test task = test after build in same pkg) |
package#task | Specific package task | "utils#build" (utils package build task) |
Common turbo.json Patterns
Pattern 1: Build with Dependencies
{
"pipeline": {
"build": {
"dependsOn": ["^build"],
"outputs": ["dist/**", ".next/**"]
}
}
}
Builds dependencies first, then this package.
Pattern 2: Test Before Build
{
"pipeline": {
"build": {
"dependsOn": ["test", "^build"],
"outputs": ["dist/**"]
}
}
}
Runs local tests, then dependency builds, then this package build.
Pattern 3: Cache-Only Tasks
{
"pipeline": {
"test": {
"cache": true,
"outputs": ["coverage/**"]
}
}
}
Tests are cached; only re-run on source code changes.
Pattern 4: Never Cache
{
"pipeline": {
"deploy": {
"cache": false
}
}
}
Useful for deployment and external API calls.
Pattern 5: Long-Running Tasks (Dev Server)
{
"pipeline": {
"dev": {
"cache": false,
"persistent": true,
"interactive": true
}
}
}
Dev servers run continuously and accept input.
CLI Commands
Run Tasks
# Run a single task in all packages
turbo run build
# Run multiple tasks
turbo run build lint test
# Run task in specific package
turbo run build --filter=ui
# Run without dependencies (immediate task only)
turbo run test --only
# Run only affected packages (git-based)
turbo run build --affected
# Run with all environment variables available
turbo run build --env-mode=loose
# Run in parallel (ignoring dependency graph)
turbo run dev --parallel
# Force re-run (ignore cache)
turbo run build --force
# Run with verbose output
turbo run build -v
turbo run build -vv # more verbose
turbo run build -vvv # very verbose
Filtering
# By package name
turbo run build --filter=web
# By directory pattern
turbo run build --filter=./apps/*
# By git changes
turbo run build --filter=[HEAD^1]
# Select dependents (packages depending on target)
turbo run build --filter=...ui
# Select dependencies (packages target depends on)
turbo run build --filter=ui...
# Exclude packages
turbo run build --filter=!admin
# Combine filters (union)
turbo run build --filter=web --filter=mobile
# Specific task in package
turbo run web#build
Cache Management
# Disable caching
turbo run build --no-cache
# Use only local cache
turbo run build --cache=local:rw
# Use only remote cache
turbo run build --cache=remote:rw
# Read-only cache
turbo run build --cache=local:r
# Disable cache completely
turbo run build --cache=local:,remote:
Other Useful Commands
# Dry run (show what would execute, don't run)
turbo run build --dry-run
# Dry run as JSON
turbo run build --dry=json
# Show task execution order without running
turbo run build --graph=mermaid
# Generate performance trace (Chrome Tracing format)
turbo run build --profile -vv
# Generate run summary (metadata about execution)
turbo run build --summarize
# Continue on error
turbo run build --continue=always
# Limit concurrency
turbo run build --concurrency=4
turbo run build --concurrency=50%
# Watch mode (watch for changes and re-run)
turbo watch run build
Remote Caching (Vercel)
# Login to Vercel
turbo login
# Link to remote cache
turbo link
# Link specific project in package
cd apps/web && turbo link
# Logout
turbo logout
# Verify remote cache is working
turbo run build --summarize
Utility Commands
# List all packages in workspace
turbo ls
# Check workspace info
turbo info
# Check package boundaries/dependencies
turbo boundaries
# Generate new package/code
turbo gen
# Prune dependency graph (for Docker/CI)
turbo prune --scope=web
# Check for missing environment variables
turbo scan
# Get Turborepo version
turbo --version
Environment Variables
Global Environment Variables (turbo.json)
{
"globalEnv": ["NODE_ENV", "API_KEY"],
"globalPassThroughEnv": ["HOME", "PATH"]
}
globalEnv: Changes invalidate ALL task cachesglobalPassThroughEnv: Available to tasks but don't affect caching
Task-Specific Environment Variables
{
"pipeline": {
"build": {
"env": ["NODE_ENV", "NEXT_PUBLIC_*"],
"passThroughEnv": ["HOME"]
}
}
}
Environment Variable Patterns
{
"env": [
"*", // All variables
"API_*", // Prefix match
"!API_SECRET", // Negation (exclude)
"NODE_ENV" // Exact match
]
}
Strict vs Loose Mode
# Strict mode (default) - only listed vars available
turbo run build --env-mode=strict
# Loose mode - all vars available (less safe for caching)
turbo run build --env-mode=loose
Package Configurations
Use for task customization per-package:
// packages/ui/turbo.json
{
"extends": ["//"],
"pipeline": {
"build": {
"outputs": ["dist/**"],
"env": ["THEME_*"]
}
}
}
Common Patterns & Best Practices
1. Workspace Dependencies
// apps/web/package.json
{
"dependencies": {
"@repo/ui": "workspace:*",
"@repo/utils": "workspace:*"
}
}
2. Shared Configuration
// Root turbo.json
{
"globalDependencies": [
"package.json",
"pnpm-lock.yaml",
".env.example"
]
}
3. CI/CD Optimization
# In GitHub Actions
turbo run build --affected --cache=remote:rw
# In other CI systems
turbo run build --force --cache=local:rw
4. Docker/Monorepo Pruning
# Prune only dependencies needed for `web` app
turbo prune --scope=web --docker
# Then in Dockerfile
COPY --from=base /repo/out/full /repo
COPY --from=base /repo/out/json .
COPY --from=base /repo/out/pnpm-lock.yaml ./pnpm-lock.yaml
RUN pnpm install --frozen-lockfile
5. Task Skipping (turbo-ignore)
# In CI environment variable
TURBO_TELEMETRY_DISABLED=1
# Skip build if only docs changed
turbo-ignore docs
Caching Strategy
What Gets Cached
- Outputs: Files specified in
outputskey - Logs: Task logs (always cached if caching enabled)
- Metadata: Task execution metadata
Cache Invalidation
Cache is invalidated when:
- Source files in
inputschange globalDependenciesfiles change- Environment variables in
envchange turbo.jsonchangespackage.jsonchanges (in that package)- Lockfile changes
Cache Locations
# Local cache (default)
.turbo/cache/
# Custom cache directory
turbo run build --cache-dir=.turbo-cache
# Or in turbo.json
{
"cacheDir": ".turbo-cache"
}
Debugging & Troubleshooting
Check Task Configuration
# See what tasks will execute
turbo run build --dry-run
# Get detailed execution info
turbo run build --dry=json | jq
# Verbose output
turbo run build -vvv
Analyze Performance
# Generate Chrome trace
turbo run build --profile -vv
# Check hash and dependencies
turbo run build --dry-run | grep -A5 "web#build"
# See execution summary
turbo run build --summarize
# View in `.turbo/runs/` directory
Common Issues
| Issue | Solution |
|---|---|
| Cache not working | Check outputs glob pattern; verify env vars in env key |
| Task not running | Check dependsOn; use --dry-run to verify task graph |
| Environment vars not available | Add to env in turbo.json for hashing, passThroughEnv for availability |
| Performance degradation | Check if inputs are too broad; optimize glob patterns |
| Package not found | Verify package.json name; use turbo ls to list packages |
Advanced Tips
1. Framework Inference
Turborepo automatically includes framework-specific env vars:
- Next.js:
NEXT_PUBLIC_*(automatic) - Nuxt:
NUXT_*(automatic) - Vue:
VUE_APP_*(automatic)
2. Multiple Package Managers
{
"packageManager": "pnpm@8.0.0"
}
3. Workspace Configuration
// pnpm-workspace.yaml
packages:
- 'apps/*'
- 'packages/*'
- 'tools/*'
// package.json (npm/yarn)
{
"workspaces": ["apps/*", "packages/*"]
}
4. Remote Cache with Custom Endpoint
{
"remoteCache": {
"apiUrl": "https://custom-cache.com",
"signature": true,
"timeout": 60,
"uploadTimeout": 120
}
}
5. Concurrency Control
# Serial execution (1 at a time)
turbo run build --concurrency=1
# Use 50% of CPU cores
turbo run build --concurrency=50%
# Or in turbo.json
{
"concurrency": "50%"
}
Real-World Example
{
"extends": ["//"],
"globalDependencies": ["*.env", "package.json"],
"pipeline": {
"build": {
"dependsOn": ["^build"],
"outputs": ["dist/**", ".next/**"],
"cache": true,
"env": ["NODE_ENV", "API_URL"]
},
"test": {
"dependsOn": ["build"],
"outputs": ["coverage/**"],
"cache": true
},
"lint": {
"cache": true,
"outputs": []
},
"type-check": {
"cache": true,
"outputs": []
},
"dev": {
"cache": false,
"persistent": true,
"interactive": true
},
"deploy": {
"cache": false,
"dependsOn": ["build", "test", "lint"]
}
}
}
Usage:
# Full CI pipeline
turbo run lint type-check test build
# Development
turbo run dev --parallel
# Deploy only changed packages
turbo run build --affected && turbo run deploy
# Rebuild everything
turbo run build --force
Resources
- Official Docs: https://turborepo.com
- API Reference: https://turborepo.com/docs/reference
- Examples: https://github.com/vercel/turborepo/tree/main/examples
- Vercel Remote Cache: https://vercel.com/docs/monorepos/turborepo
Quick Command Reference
# Development
turbo run dev --parallel
# Build
turbo run build
# Lint
turbo run lint
# Test
turbo run test
# All checks before commit
turbo run lint type-check test
# Force rebuild everything
turbo run build --force
# Only affected packages
turbo run build --affected
# Specific package
turbo run build --filter=web
# Watch mode
turbo watch run build
# See what would run
turbo run build --dry-run
# Performance analysis
turbo run build --profile -vv
# Remote cache
turbo login
turbo link
turbo run build
Last Updated: December 2025 | Based on Turborepo latest documentation