| name | turborepo |
| description | Configures Turborepo v2.8 monorepo pipelines including turbo.json tasks, remote cache, filter and affected CI, boundaries, and microfrontend deploys. Use when orchestrating JS/TS workspace builds or optimizing turbo CI. Not for a single Next.js app with no shared packages, Vercel Functions runtimes (vercel-functions), or package-manager workspaces that never invoke turbo. |
| version | 1.0.1 |
| 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|watch|prune|ls|login|link|devtools|docs|boundaries)\\b","\\bnpx\\s+turbo\\b","\\bbunx\\s+turbo\\b","\\bnpx\\s+create-turbo\\b","\\bnpx\\s+@turbo/codemod\\b"]} |
Turborepo
You are an expert in Turborepo v2.8 — the high-performance, Rust-powered build system for JavaScript/TypeScript monorepos by Vercel. Provide precise, actionable guidance for task pipelines, caching, filtering, CI optimization, and architectural boundary enforcement.
When to Use
Activate this skill when the user is working with any of the following:
- turbo.json configuration — defining task pipelines, outputs, inputs, env vars, cache rules
- Monorepo build orchestration — multiple apps or packages sharing code
- CI optimization —
--affected flag, remote caching, dynamic matrix jobs
- Workspace filtering —
--filter syntax for scoped task execution
- Boundary enforcement — architectural constraints via
boundaries in turbo.json
- Microfrontend orchestration — independent deploys with shared packages
- Bun workspace support — lockfile detection, granular cache invalidation
- Upgrading Turborepo — codemod migration, version-specific features
Do NOT recommend Turborepo for a single Next.js app without shared code — standard Turopack or Next.js built-in tooling is simpler.
Prerequisites
- Node.js 18+ (Node 22 recommended for latest features)
- Package manager: npm, pnpm, yarn, or Bun (Bun support stable since 2.6; requires
bun.lock text format)
- Git — required for
--affected and --filter=[branch] to compute changed files
- Windows host (PowerShell): Commands below use POSIX-style flags. In PowerShell, wrap glob patterns in single quotes or use
--filter='web...' to avoid splatting issues. For multi-line YAML in CI, use standard GitHub Actions runners (Ubuntu) — Windows runners are supported but not primary for CI.
Procedure
1. Install or Upgrade Turborepo
npx create-turbo@latest
npm install turbo --save-dev
npx @turbo/codemod migrate
2. Define turbo.json Task Pipeline
Create or edit turbo.json at the repository root:
{
"$schema": "https://turborepo.dev/schema.json",
"globalDependencies": [".env"],
"globalEnv": ["CI", "NODE_ENV"],
"tasks": {
"build": {
"description": "Compile TypeScript and bundle the application",
"dependsOn": ["^build"],
"outputs": [".next/**", "dist/**"],
"env": ["DATABASE_URL", "NEXT_PUBLIC_API_URL"],
"inputs": ["src/**", "package.json"
Key configuration fields:
| Field | Meaning |
|---|
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 (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 |
3. Composable Configuration (2.7+)
Package-level turbo.json can extend from any workspace package:
{
"extends": ["@myorg/config"],
"tasks": {
"build": {
"outputs": ["dist/**"]
}
}
}
4. Run Tasks with Workspace Filtering
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 |
5. Use --affected for Incremental CI
The single most important CI optimization:
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
6. Set Up Remote Caching
turbo login
turbo link
turbo build
For CI, set environment variables (use placeholders — never commit real tokens):
TURBO_TOKEN=YOUR_TOKEN
TURBO_TEAM=YOUR_TEAM
turbo build
7. Configure CI Pipeline (GitHub Actions)
Basic parallel job with --affected:
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 }}
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 }}
8. Enforce Architectural Boundaries
Add boundaries to turbo.json:
{
"boundaries": {
"tags": {
"apps/*": ["app"],
"packages/ui": ["shared", "ui"],
"packages/utils": ["shared"],
"packages/config": ["config"]
},
"rules": [
{ "from": ["app"], "allow": ["shared"] },
{ "from": ["shared"], "deny"
Check compliance:
turbo boundaries
Add to your pipeline:
{
"tasks": {
"check": {
"dependsOn": ["lint", "typecheck", "boundaries"]
},
"boundaries": {}
}
}
9. Use Watch Mode for Development
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).
10. Visualize and Dry-Run the Task Graph
turbo build --graph
turbo build --graph=graph.dot
turbo build --graph=graph.json
turbo build --graph=graph.html
turbo build --dry-run
turbo build --dry-run=json
11. Prune for Single-App Deployment
turbo prune web --docker
12. Devtools & AI Docs (2.8+)
turbo devtools
turbo docs
turbo docs output is optimized for AI coding agents — markdown format preserves context windows.
13. Bun Workspace Support (2.6+)
bun install --save-text-lockfile
turbo build --affected
Turborepo parses bun.lock (text format) for granular cache invalidation — only affected tasks are invalidated, not the entire monorepo. If only bun.lockb (binary) is found, Turborepo errors with a prompt to generate a text lockfile.
14. Microfrontend Orchestration
Structure for independent deploys with shared packages:
my-platform/
├── turbo.json
├── package.json
├── apps/
│ ├── shell/ # Layout / shell app (owns top-level routing)
│ ├── dashboard/ # Micro-app
│ ├── settings/ # Micro-app
│ └── marketing/ # Micro-app
└── packages/
├── ui/ # Shared component library
├── auth/ # Shared auth utilities
└── config/ # Shared tsconfig, eslint
turbo build --filter=dashboard
turbo build --filter=./apps/*
turbo build --filter=./apps/*...[main]
Combine with 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 |
Pitfalls
fetch-depth: 0 is mandatory for --affected — Without full git history, Turborepo cannot compute changed files. Always set fetch-depth: 0 in actions/checkout.
- Bun binary lockfile (
bun.lockb) is not supported — Turborepo requires bun.lock text format. Run bun install --save-text-lockfile to generate it. Without it, Turborepo errors.
turbo prune with Bun 1.3+ may produce broken lockfiles — Known issue: formatting differences can break bun i --frozen-lockfile. Track fixes at turborepo#11007.
- Forgetting
outputs means no caching — If you don't declare outputs, Turborepo caches the task exit code but not artifacts. Always specify build output directories.
persistent: true tasks cannot be cached — Always set cache: false alongside persistent: true for dev servers. Turbo will warn if you don't.
inputs too narrow can cause stale caches — If you specify inputs and miss a file (e.g., .env), changes to that file won't invalidate the cache. Use globalDependencies for root-level files.
- PowerShell glob splatting — In PowerShell,
--filter=web... may be interpreted as splatting. Wrap in single quotes: --filter='web...'.
- Remote cache token leakage — Never hardcode
TURBO_TOKEN in source files or turbo.json. Use CI secrets or .env (gitignored). Use YOUR_TOKEN placeholders in documentation.
^build vs build confusion — ^build means "build my dependencies first" (topological). build (no ^) means "build this same package first" (sequential within package). Mixing these up causes circular dependencies or missing builds.
- Composable config
extends requires published package — The extends field references a workspace package name, not a file path. The package must exist in the workspace and be resolvable.
Verification
Verify Turborepo is installed and version is correct
npx turbo --version
Verify task graph is valid
turbo build --dry-run
Verify caching works
turbo build
turbo build
Verify --affected detects changes correctly
git checkout -b test-affected
echo "// test" >> packages/ui/src/index.ts
git add -A && git commit -m "test"
turbo build --affected
Verify boundary rules pass
turbo boundaries
Verify remote cache is connected
turbo login
turbo link
turbo build
Verify Bun lockfile compatibility
ls bun.lock
bun install --save-text-lockfile
ls bun.lock
Examples
Minimal turbo.json for a Next.js + API monorepo
{
"$schema": "https://turborepo.dev/schema.json",
"tasks": {
"build": {
"dependsOn": ["^build"],
"outputs": [".next/**", "dist/**"]
},
"dev": {
"cache": false,
"persistent": true
},
"lint": {},
"test": {
"dependsOn": ["build"]
}
}
}
Standard monorepo structure
my-monorepo/
├── turbo.json
├── package.json
├── apps/
│ ├── web/ # Next.js app
│ ├── api/ # Backend service
│ └── docs/ # Documentation site
├── packages/
│ ├── ui/ # Shared component library
│ ├── config/ # Shared configs (eslint, tsconfig)
│ └── utils/ # Shared utilities
└── node_modules/
Related skills
- nextjs — Next.js app configuration and deployment
- vercel — Vercel deployment platform integration
- github-actions — CI/CD pipeline configuration
- bun — Bun runtime and package manager
Official Documentation