turborepo
| Turborepo monorepo build system guidance. Triggers on: turbo.json, task pipelines, dependsOn, caching, remote cache, the "turbo" CLI, --filter, --affected, CI optimization, environment variables, internal packages, monorepo structure/best practices, and boundaries. Use when user: configures tasks/
By secondsky · 363 installs
npx skills add secondsky/claude-skills --skill turborepo
Source repository · Upstream listing
Turborepo Skill
Build system for JavaScript/TypeScript monorepos. Turborepo caches task outputs and runs tasks in parallel based on dependency graph.
IMPORTANT: Package Tasks, Not Root Tasks
DO NOT create Root Tasks. ALWAYS create package tasks.
When creating tasks/scripts/pipelines, you MUST:
1. Add the script to each relevant package's package.json
2. Register the task in root turbo.json
3. Root package.json only delegates via turbo run <task
DO NOT put task logic in root package.json . This defeats Turborepo's parallelization.
Root Tasks ( // taskname ) are ONLY for tasks that truly cannot exist in packages (rare).
Secondary Rule: turbo run vs turbo
Always use turbo run when the command is written into code:
The shorthand turbo <tasks is ONLY for one off terminal commands typed directly by humans or agents. Never write turbo build into package.json, CI, or scripts.
Quick Decision Trees
"I need to configure a task"
"My cache isn't working"
"I want to run only changed packages"
affected is the primary way to run only changed packages. It automatically compares against the default branch and includes dependents.
"I want to filter packages"
"Environment variables aren't working"
"I need to set up CI"
"I want to watch for changes during development"
"I need to create/structure a package"
"How should I structure my monorepo?"
"I want to enforce architectural boundaries"
Critical Anti Patterns
Using turbo Shorthand in Code
turbo run is recommended in package.json scripts and CI pipelines. The shorthand turbo <task is intended for interactive terminal use.
Root Scripts Bypassing Turbo
Root package.json scripts MUST delegate to turbo run , not run tasks directly.
Using && to Chain Turbo Tasks
Don't chain turbo tasks with && . Let turbo orchestrate.
prebuild Scripts That Manually Build Dependencies
Scripts like prebuild that manually build other packages bypass Turborepo's dependency graph.
However, the fix depends on whether workspace dependencies are declared:
1. If dependencies ARE declared (e.g., "@repo/types": "workspace: " in package.json), remove the prebuild script. Turbo's dependsOn: ["^build"] handles this automatically.
2. If dependencies are NOT declared , the prebuild exists because ^build won't trigger without a dependency relationship. The fix is to:
Add the dependency to package.json: "@repo/types": "workspace: "
Then remove the prebuild script
Key insight: ^build only runs build in packages listed as dependencies. No dependency declaration = no automatic build ordering.
Overly Broad globalDependencies
globalDependencies affects ALL tasks in ALL packages. Be specific.
Repetitive Task Configuration
Look for repeated configuration across tasks that can be collapsed. Turborepo supports shared configuration patterns.
When to use global vs task level:
globalEnv / globalDependencies affects ALL tasks, use for truly shared config
Task level env / inputs use when only specific tasks need it
NOT an Anti Pattern: Large env Arrays
A large env array (even 50+ variables) is not a problem. It usually means the user was thorough about declaring their build's environment dependencies. Do not flag this as an issue.
Using parallel Flag
The parallel flag bypasses Turborepo's dependency graph. If tasks need parallel execution, configure dependsOn correctly instead.
Package Specific Task Overrides in Root turbo.json
When multiple packages need different task configurations, use Package Configurations ( turbo.json in each package) instead of cluttering root turbo.json with package task overrides.
Benefits of Package Configurations:
Keeps configuration close to the code it affects
Root turbo.json stays clean and focused on base patterns
Easier to understand what's special about each package
Works with $TURBO EXTENDS$ to inherit + extend arrays
When to use package task in root:
Single package needs a unique dependency (e.g., "deploy": { "dependsOn": ["web build"] } )
Temporary override while migrating
See references/configuration/RULE.md package configurations for full details.
Using ../ to Traverse Out of Package in inputs
Don't use relative paths like ../ to reference files outside the package. Use $TURBO ROOT$ instead.
Missing outputs for File Producing Tasks
Before flagging missing outputs , check what the task actually produces:
1. Read the package's script (e.g., "build": "tsc" , "test": "vitest" )
2. Determine if it writes files to disk or only outputs to stdout
3. Only flag if the task produces files that should be cached
Common outputs by framework:
Next.js: [".next/ ", "!.next/cache/ "]
Vite/Rollup: ["dist/ "]
tsc: ["dist/ "] or custom outDir
TypeScript noEmit can still produce cache files:
When incremental: true in tsconfig.json, tsc noEmit writes .tsbuildinfo files even without emitting JS. Check the tsconfig before assuming no outputs:
To determine correct outputs for TypeScript tasks:
1. Check if incremental or composite is enabled in tsconfig
2. Check tsBuildInfoFile for custom cache location (default: alongside outDir or in project root)
3. If no incremental mode, tsc noEmit produces no files
^build vs build Confusion
Environment Variables Not Hashed
.env Files Not in Inputs
Turbo does NOT load .env files your framework does. But Turbo needs to know about changes:
Root .env File in Monorepo
A .env file at the repo root is an anti pattern — even for small monorepos or starter templates. It creates implicit coupling between packages and makes it unclear which packages depend on which variables.
Problems with root .env :
Unclear which packages consume which variables
All packages get all variables (even ones they don't need)
Cache invalidation is coarse grained (root .env change invalidates everything)
Security risk: packages may accidentally access sensitive vars meant for others
Bad habits start small — starter templates should model correct patterns
If you must share variables , use globalEnv to be explicit about what's shared, and document why.
Strict Mode Filtering CI Variables
By default, Turborepo filters environment variables to only those in env / globalEnv . CI variables may be missing:
Or use env mode=loose (not recommended for production).
Shared Code in Apps (Should Be a Package)
Accessing Files Across Package Boundaries
Too Many Root Dependencies
Common Task Configurations
Standard Build Pipeline
Add a transit task if you have tasks that need parallel execution with cache invalidation (see below).
Dev Task with ^dev Pattern (for turbo watch )
A dev task with dependsOn: ["^dev"] and persistent: false in root turbo.json may look unusual but is correct for turbo watch workflows :
Why this works:
Packages (e.g., @acme/db , @acme/validators ) have "dev": "tsc" — one shot type generation that completes quickly
Apps override with persistent: true for actual dev servers (Next.js, etc.)
turbo watch re runs the one shot package dev scripts when source files change, keeping types in sync
Intended usage: Run turbo watch dev (not turbo run dev ). Watch mode re executes one shot tasks on file changes while keeping persistent tasks running.
Alternative pattern: Use a separate task name like prepare or generate for one shot dependency builds to make the intent clearer:
Transit Nodes for Parallel Tasks with Cache Invalidation
Some tasks can run in parallel (don't need built output from dependencies) but must invalidate cache when dependency source code changes.
The problem with dependsOn: ["^taskname"] :
Forces sequential execution (slow)
The problem with dependsOn: [] (no dependencies):
Allows parallel execution (fast)
But cache is INCORRECT changing dependency source won't invalidate cache
Transit Nodes solve both:
The transit task creates dependency relationships without matching any actual script, so tasks run in parallel with correct cache invalidation.
How to identify tasks that need this pattern: Look for tasks that read source files from dependencies but don't need their build outputs.
With Environment Variables
When to Load References
Load references/configuration/ when:
RULE.md : Need overview of turbo.json structure
tasks.md : Defining task configuration (dependsOn, outputs, inputs, env, cache)
global options.md : Setting up globalEnv, globalDependencies, cacheDir, daemon
gotchas.md : Encountering unexpected configuration behavior
Load references/caching/ when:
RULE.md : Understanding how cache hashing works
remote cache.md : Setting up Vercel Remote Cache or self hosted cache
gotchas.md : Debugging cache misses or using summarize/ dry flags
Load references/environment/ when:
RULE.md : Configuring environment variables (env, globalEnv, passThroughEnv)
modes.md : Choosing strict vs loose mode, framework inference
gotchas.md : Troubleshooting .env files or CI environment issues
Load references/filtering/ when:
RULE.md : Need filter syntax overview
patterns.md : Building complex filter patterns for selective runs
Load references/ci/ when:
RULE.md : General CI principles and caching strategies
github actions.md : Complete GitHub Actions workflow setup
vercel.md : Vercel deployment setup with turbo ignore
patterns.md : Implementing affected flag patterns and optimization
Load references/cli/ when:
RULE.md : Basic turbo run command usage
commands.md : Complete CLI reference including turbo ignore and flags
Load references/best practices/ when:
RULE.md : Monorepo structure and organization overview
structure.md : Repository layout, workspace config, TypeScript/ESLint setup
packages.md : Creating internal packages, JIT vs Compiled strategies, exports
dependencies.md : Dependency management patterns, version sync
Load references/watch/ when:
RULE.md : Setting up turbo watch for development workflows
Load references/boundaries/ when:
RULE.md : Enforcing package isolation with experimental boundaries feature
Reference Index
Configuration
File Purpose
[configuration/RULE.md](./references/configuration/RULE.md) turbo.json overview, Package Configurations
[configuration/tasks.md](./references/configuration/tasks.md) dependsOn, outputs, inputs, env, cache, persistent
[configuration/global options.md](./references/configuration/global options.md) globalEnv, globalDependencies, cacheDir, daemon, envMode
[configuration/gotchas.md](./references/configuration/gotchas.md) Common configuration mistakes
Caching
File Purpose
[caching/RULE.md](./references/caching/RULE.md) How caching works, hash inputs
[caching/remote cache.md](./references/caching/remote cache.md) Vercel Remote Cache, self hosted, login/link
[caching/gotchas.md](./references/caching/gotchas.md) Debugging cache misses, summarize, dry
Environment Variables
File Purpose
[environment/RULE.md](./references/environment/RULE.md) env, globalEnv, passThroughEnv