| name | turborepo |
| description | Turborepo expert guidance. Use when setting up or optimizing monorepo builds, configuring task caching, remote caching, parallel execution, or the --affected flag for incremental CI. |
| metadata | {"priority":5,"docs":["https://turborepo.dev/docs"],"sitemap":"https://turborepo.dev/sitemap.xml","pathPatterns":["turbo.json","turbo/**"],"bashPatterns":["\\bturbo\\s+(run|build|test|lint|dev)\\b","\\bnpx\\s+turbo\\b","\\bbunx\\s+turbo\\b"]} |
Turborepo
You are an expert in Turborepo v2.10 — "the build system for agentic coding" — a high-performance build system for JavaScript/TypeScript monorepos, built by Vercel with a Rust-powered core.
Key Features
- Task caching: Content-aware hashing — only rebuilds when files actually change
- Remote caching: Share build caches across machines and CI via Vercel
- Parallel execution: Uses all CPU cores automatically
- Incremental builds:
--affected flag runs only changed packages + dependents
- Pruned subsets: Generate minimal monorepo for deploying a single app
- Dependency graph awareness: Understands package relationships
- Git worktree cache sharing: Automatically shares local cache across worktrees (2.8+)
- Devtools: Visual package and task graph explorer via
turbo devtools (2.8+)
- Composable configuration: Extend
turbo.json from any package, not just root (2.7+)
- AI-enabled docs:
turbo docs returns markdown responses optimized for AI agents (2.8+)
Setup
npx create-turbo@latest
npm install turbo --save-dev
npx @turbo/codemod migrate
turbo.json Task Pipeline
The turbo.json file defines your task dependency graph. Here are comprehensive examples:
Basic pipeline
{
"$schema": "https://turborepo.dev/schema.json",
"tasks": {
"build": {
"description": "Compile TypeScript and bundle the application",
"dependsOn": ["^build"],
"outputs": [".next/**", "dist/**"]
},
"test": {
"description": "Run the test suite",
"dependsOn": ["build"]
},
"lint": {
"description": "Lint source files"
},
"dev": {
"cache":
Advanced pipeline with environment variables and inputs
{
"$schema": "https://turborepo.dev/schema.json",
"globalDependencies": [".env"],
"globalEnv": ["CI", "NODE_ENV"],
"tasks": {
"build": {
"dependsOn": ["^build"],
"outputs": [".next/**", "dist/**"],
"env": ["DATABASE_URL", "NEXT_PUBLIC_API_URL"],
"inputs": ["src/**", "package.json", "tsconfig.json"]
},
Key Configuration
dependsOn: ["^build"] — Run build in dependencies first (^ = topological)
dependsOn: ["build"] — Run build in the same package first (no ^)
outputs — Files to cache (build artifacts)
inputs — Files that affect the task hash (default: all non-gitignored files)
env — Environment variables that affect the task hash
cache: false — Skip caching (for dev servers, codegen)
persistent: true — Long-running tasks (dev servers)
globalDependencies — Files that invalidate all task caches when changed
globalEnv — Env vars that invalidate all task caches when changed
Workspace Filtering
Run tasks in specific packages or subsets of your monorepo:
turbo build --filter=web
turbo build --filter=web...
turbo build --filter=...ui
turbo build --filter=web --filter=api
turbo build --filter=./apps/*
turbo build --filter=[main]
turbo build --filter=...[main]
turbo build --filter=!docs
turbo build --filter=@myorg/*
Filter syntax reference
| Pattern | Meaning |
|---|
web | Only the web package |
web... | web and all its dependencies |
...web | web and all its dependents |
...web... | web, its dependencies, and its dependents |
./apps/* | All packages in the apps/ directory |
[main] | Packages changed since main branch |
{./apps/web}[main] | web only if it changed since main |
!docs | Exclude the docs package |
CI Matrix Strategies
GitHub Actions — parallel jobs per package
name: CI
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-node@v4
with:
node-version: 22
- run: npm ci
- run: turbo build test lint --affected
env:
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
TURBO_TEAM: ${{ vars.TURBO_TEAM }}
deploy-web:
needs: build
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
Dynamic matrix from workspace list
jobs:
detect:
runs-on: ubuntu-latest
outputs:
packages: ${{ steps.list.outputs.packages }}
steps:
- uses: actions/checkout@v4
- id: list
run: |
PACKAGES=$(turbo ls --affected --output=json | jq -c '[.[].name]')
echo "packages=$PACKAGES" >> "$GITHUB_OUTPUT"
test:
needs: detect
if: needs.detect.outputs.packages != '[]'
runs-on: ubuntu-latest
strategy:
matrix:
package: ${{ fromJson(needs.detect.outputs.packages) }}
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: turbo test --filter=${{ matrix.package }}
Remote caching in CI
TURBO_TOKEN=your-vercel-token
TURBO_TEAM=your-vercel-team
turbo build
Watch Mode
Run tasks in watch mode for development — re-executes when source files change:
turbo watch test
turbo watch test --filter=web
turbo watch test lint
Watch mode respects the task graph — if test depends on build, changing a source file re-runs build first, then test.
Persistent tasks vs watch
persistent: true in turbo.json: The task itself is long-running (e.g., next dev). Turbo starts it and keeps it alive.
turbo watch: Turbo re-invokes the task on file changes. Use for tasks that run and exit (e.g., vitest run, tsc --noEmit).
Boundary Rules
Enforce architectural constraints across your monorepo with boundaries in turbo.json:
{
"boundaries": {
"tags": {
"apps/*": ["app"],
"packages/ui": ["shared", "ui"],
"packages/utils": ["shared"],
"packages/config": ["config"]
},
"rules": [
{
"from": ["app"],
"allow": ["shared"]
},
{
"from": ["shared"],
"deny"
This enforces:
- Apps can import shared packages
- Shared packages cannot import from apps
- Violations produce build-time errors with
turbo boundaries
turbo boundaries
{
"tasks": {
"check": {
"dependsOn": ["lint", "typecheck", "boundaries"]
},
"boundaries": {}
}
}
Graph Visualization
Inspect your task dependency graph:
turbo build --graph
turbo build --graph=graph.dot
turbo build --graph=graph.json
turbo build --graph=graph.html
Dry run — see what would execute
turbo build --dry-run
turbo build --dry-run=json
The dry run output shows:
- Each task that would execute
- Cache status (HIT or MISS)
- Dependencies and dependents
- File hash used for caching
Devtools & Docs (2.8+)
turbo devtools
turbo docs
npx @turbo/codemod migrate
Note: turbo docs output is optimized for AI coding agents — markdown format preserves context windows. The docs site also includes sample prompts for common tasks you can copy directly into your agent.
Composable Configuration (2.7+)
Package configs can now extend from any workspace package, not just the root:
{
"extends": ["@myorg/config"],
"tasks": {
"build": {
"outputs": ["dist/**"]
}
}
}
Common Commands
turbo build
turbo build --affected
turbo build --filter=web
turbo build --remote-cache
turbo prune web --docker
turbo ls
turbo ls --affected
Remote Caching
turbo login
turbo link
turbo build
Monorepo Structure
my-monorepo/
├── turbo.json
├── package.json
├── apps/
│ ├── web/ # Next.js app
│ │ └── package.json
│ ├── api/ # Backend service
│ │ └── package.json
│ └── docs/ # Documentation site
│ └── package.json
├── packages/
│ ├── ui/ # Shared component library
│ │ └── package.json
│ ├── config/ # Shared configs (eslint, tsconfig)
│ │ └── package.json
│ └── utils/ # Shared utilities
│ └── package.json
└── node_modules/
--affected Flag
The most important optimization for CI pipelines:
turbo build test lint --affected
This performs intelligent graph traversal:
- Identifies changed files since the base branch
- Maps changes to affected packages
- Includes all dependent packages (transitively)
- Runs tasks only for the affected subgraph
Microfrontends & Multi-App Composition
Turborepo is the recommended orchestration layer for Vercel's Microfrontends architecture — composing multiple independently-deployed apps behind a single URL.
Monorepo Structure for Microfrontends
my-platform/
├── turbo.json
├── package.json
├── apps/
│ ├── shell/ # Layout / shell app (owns top-level routing)
│ ├── dashboard/ # Micro-app: dashboard features
│ ├── settings/ # Micro-app: settings features
│ └── marketing/ # Micro-app: public marketing site
└── packages/
├── ui/ # Shared component library
├── auth/ # Shared auth utilities
└── config/ # Shared tsconfig, eslint
Independent Deploys
Each micro-app is a separate Vercel project with its own build and deploy lifecycle:
turbo build --filter=dashboard
turbo build --filter=./apps/*
turbo build --filter=./apps/*...[main]
Shared Packages Across Micro-Apps
Use Turborepo's dependency graph to share code without coupling deploys:
{
"tasks": {
"build": {
"dependsOn": ["^build"],
"outputs": [".next/**", "dist/**"]
}
}
}
Shared packages (ui, auth, config) are built first via ^build, then each micro-app builds against the latest shared code. Remote caching ensures shared package builds are never repeated across micro-app deploys.
Multi-Zone Patterns
Next.js multi-zones let each micro-app own a URL path prefix while sharing a single domain:
import type { NextConfig } from 'next'
const nextConfig: NextConfig = {
async rewrites() {
return [
{ source: '/dashboard/:path*', destination: 'https://dashboard.example.com/dashboard/:path*' },
{ source: '/settings/:path*', destination: 'https://settings.example.com/settings/:path*' },
]
},
}
export default nextConfig
Combine with Turborepo boundary rules to enforce architectural isolation:
{
"boundaries": {
"tags": {
"apps/*": ["micro-app"],
"packages/ui": ["shared"],
"packages/auth": ["shared"]
},
"rules": [
{ "from": ["micro-app"], "allow": ["shared"] },
{ "from": ["shared"], "deny": ["micro-app"] }
]
}
}
When to Use Turborepo for Microfrontends
| Scenario | Recommended? |
|---|
| Multiple teams owning independent features | Yes — independent deploys + shared packages |
| Single team, single app | No — standard Next.js is simpler |
| Shared component library across apps | Yes — packages/ui with boundary rules |
| Gradual migration from monolith | Yes — extract features into micro-apps incrementally |
| Need version-skew protection | Yes — isolated builds per micro-app |
Related Documentation
Bun Support & Lockfile Detection
Turborepo 2.6+ has stable Bun support with granular lockfile analysis:
- Lockfile format: Turborepo requires
bun.lock (text format). If only bun.lockb (binary) is found, it errors with a prompt to generate a text lockfile. Generate with bun install --save-text-lockfile.
- Granular cache invalidation: Turborepo parses
bun.lock to detect which specific packages changed and only invalidates caches for affected tasks — not the entire monorepo.
- Pruning:
turbo prune works with Bun workspaces, generating a minimal lockfile for single-app deploys.
- Skip-builds detection: On Vercel, monorepo workspace detection automatically skips unaffected projects when
bun.lock changes don't touch a project's dependencies. Combined with --affected, only changed packages and their dependents rebuild.
bun install --save-text-lockfile
turbo build --affected
Deploying to Vercel
Vercel auto-detects Turborepo and optimizes builds. Each app in apps/ can be a separate Vercel project with automatic dependency detection.
When to Use Turborepo
| Scenario | Use Turborepo? |
|---|
| Single Next.js app | No — Turbopack handles bundling |
| Multiple apps sharing code | Yes — orchestrate builds |
| Shared component library | Yes — manage dependencies |
| CI taking too long | Yes — caching + affected |
| Team sharing build artifacts | Yes — remote caching |
| Enforcing architecture boundaries | Yes — boundary rules |
| Complex multi-step CI pipelines | Yes — task graph + matrix |
Official Documentation