Turborepo
Build system orchestration with Turborepo for high-performance monorepo task running and caching
You are an expert in Turborepo for managing monorepo build systems, task orchestration, and remote caching. ## Key Points - `"dependsOn": ["^build"]` — Run `build` in all dependency packages first (topological). - `"dependsOn": ["build"]` — Run `build` in the same package first. - `"dependsOn": ["^build", "type-check"]` — Combine both topological and same-package deps. 1. **Define all outputs explicitly** — Turborepo caches based on outputs; missing outputs means broken cache restores. 2. **Use `inputs` to narrow cache keys** — Specify only relevant source files so unrelated changes don't bust the cache. 3. **Never cache `dev`** — Set `"cache": false` and `"persistent": true` for long-running dev servers. 4. **Declare environment variables** — Use `env` and `globalEnv` so environment changes correctly invalidate caches. 5. **Use `--filter` in CI** — Only build and test affected packages to cut CI time dramatically. 6. **Enable Remote Caching** — Share cache across CI runs and team members to avoid redundant work. 7. **Use `--dry-run`** — Debug task graphs with `turbo run build --dry-run` to verify what will execute. - **Missing `^` in dependsOn** — `"dependsOn": ["build"]` runs build in the *same* package; `"dependsOn": ["^build"]` runs it in *dependencies*. Confusing these breaks the build order. - **Not listing all outputs** — If a build produces files outside `dist/`, cache restores will be incomplete and builds will appear to succeed but have missing artifacts. ## Quick Example ```bash # Create a new Turborepo npx create-turbo@latest # Add to an existing monorepo npm install turbo --save-dev ```
skilldb get monorepo-skills/TurborepoFull skill: 175 linesTurborepo — Monorepo Management
You are an expert in Turborepo for managing monorepo build systems, task orchestration, and remote caching.
Core Philosophy
Overview
Turborepo is a high-performance build system for JavaScript and TypeScript monorepos. It provides intelligent task scheduling, local and remote caching, and incremental builds. Turborepo understands your dependency graph and runs tasks in the optimal order with maximum parallelism.
Setup & Configuration
Installation
# Create a new Turborepo
npx create-turbo@latest
# Add to an existing monorepo
npm install turbo --save-dev
turbo.json Configuration
{
"$schema": "https://turbo.build/schema.json",
"globalDependencies": ["**/.env.*local"],
"globalEnv": ["NODE_ENV"],
"pipeline": {
"build": {
"dependsOn": ["^build"],
"outputs": ["dist/**", ".next/**", "!.next/cache/**"],
"env": ["NEXT_PUBLIC_API_URL"]
},
"test": {
"dependsOn": ["build"],
"inputs": ["src/**/*.tsx", "src/**/*.ts", "test/**/*.ts"],
"outputs": ["coverage/**"]
},
"lint": {
"outputs": []
},
"dev": {
"cache": false,
"persistent": true
},
"type-check": {
"dependsOn": ["^build"],
"outputs": []
}
}
}
Package-Level Configuration
In each package's package.json:
{
"name": "@myorg/web",
"scripts": {
"build": "next build",
"dev": "next dev",
"lint": "eslint .",
"test": "vitest run"
}
}
Core Patterns
Task Dependencies
"dependsOn": ["^build"]— Runbuildin all dependency packages first (topological)."dependsOn": ["build"]— Runbuildin the same package first."dependsOn": ["^build", "type-check"]— Combine both topological and same-package deps.
Filtering
# Run build only in @myorg/web and its dependencies
turbo run build --filter=@myorg/web...
# Run tests in all packages that changed since main
turbo run test --filter=...[main]
# Run lint in packages under apps/
turbo run lint --filter=./apps/*
# Exclude a package
turbo run build --filter=!@myorg/docs
Remote Caching
# Login to Vercel Remote Cache
turbo login
# Link your repo
turbo link
# Or self-host with environment variables
TURBO_TOKEN=your-token
TURBO_TEAM=your-team
TURBO_API=https://your-cache-server.com
Environment Variable Handling
{
"pipeline": {
"build": {
"env": ["DATABASE_URL", "API_SECRET"],
"passThroughEnv": ["CI", "GITHUB_TOKEN"]
}
}
}
Outputs Configuration
{
"pipeline": {
"build": {
"outputs": ["dist/**", "build/**", ".next/**", "!.next/cache/**"]
},
"test": {
"outputs": ["coverage/**"]
},
"lint": {
"outputs": []
}
}
}
Best Practices
- Define all outputs explicitly — Turborepo caches based on outputs; missing outputs means broken cache restores.
- Use
inputsto narrow cache keys — Specify only relevant source files so unrelated changes don't bust the cache. - Never cache
dev— Set"cache": falseand"persistent": truefor long-running dev servers. - Declare environment variables — Use
envandglobalEnvso environment changes correctly invalidate caches. - Use
--filterin CI — Only build and test affected packages to cut CI time dramatically. - Enable Remote Caching — Share cache across CI runs and team members to avoid redundant work.
- Use
--dry-run— Debug task graphs withturbo run build --dry-runto verify what will execute.
Common Pitfalls
- Missing
^in dependsOn —"dependsOn": ["build"]runs build in the same package;"dependsOn": ["^build"]runs it in dependencies. Confusing these breaks the build order. - Not listing all outputs — If a build produces files outside
dist/, cache restores will be incomplete and builds will appear to succeed but have missing artifacts. - Forgetting environment variables in config — Turborepo won't know to invalidate the cache when an env var changes unless it's declared in
envorglobalEnv. - Caching non-deterministic tasks — Tasks that depend on timestamps or random values will produce stale results from cache.
- Using
turbo runfor scripts that modify the workspace — Tasks likecodegenthat write tonode_modulesor change source files can corrupt cache state if not handled carefully.
Anti-Patterns
Over-engineering for hypothetical scale. Building for millions of users when you have hundreds adds complexity without value. Solve today's problems first.
Ignoring the existing ecosystem. Reinventing functionality that mature libraries already provide well wastes time and introduces unnecessary risk.
Premature abstraction. Creating elaborate frameworks and utilities before you have enough concrete cases to know what the abstraction should look like produces the wrong abstraction.
Neglecting error handling at boundaries. Internal code can trust its inputs, but system boundaries (user input, APIs, file I/O) require defensive validation.
Skipping documentation for obvious code. What is obvious to you today will not be obvious to your colleague next month or to you next year.
Install this skill directly: skilldb add monorepo-skills
Related Skills
Changesets
Versioning and changelog management with Changesets for coordinated monorepo package releases
CI Optimization
CI/CD optimization for monorepos including affected detection, caching strategies, and parallel execution
Dependency Management
Managing internal package dependencies, versioning strategies, and dependency graph health in monorepos
Lerna
Multi-package repository management with Lerna for versioning, publishing, and task orchestration
Nx
Monorepo development with Nx including project graph, generators, executors, and computation caching
Pnpm Workspaces
Managing monorepo packages with pnpm workspaces including linking, filtering, and dependency hoisting