turborepo · diff

v2.9.7-canary.14 to v2.9.7-canary.14

41 added, 923 removed. Audit A to A.

---
name: turborepo
- description: |
- 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/workflows/pipelines, creates packages, sets up
- monorepo, shares code between apps, runs changed/affected packages, debugs cache,
- or has apps/packages directories.
+ description: "Turborepo monorepo build-system guidance — turbo.json task pipelines, caching, the turbo CLI, --filter/--affected, CI, env vars, and packages. Use when configuring tasks, sharing code between apps, or debugging the cache."
metadata:
version: 2.9.7-canary.14
---
# 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.
-
- ```json
- // DO THIS: Scripts in each package
- // apps/web/package.json
- { "scripts": { "build": "next build", "lint": "eslint .", "test": "vitest" } }
-
- // apps/api/package.json
- { "scripts": { "build": "tsc", "lint": "eslint .", "test": "vitest" } }
-
- // packages/ui/package.json
- { "scripts": { "build": "tsc", "lint": "eslint .", "test": "vitest" } }
- ```
-
- ```json
- // turbo.json - register tasks
- {
- "tasks": {
- "build": { "dependsOn": ["^build"], "outputs": ["dist/**"] },
- "lint": {},
- "test": { "dependsOn": ["build"] }
- }
- }
- ```
-
- ```json
- // Root package.json - ONLY delegates, no task logic
- {
- "scripts": {
- "build": "turbo run build",
- "lint": "turbo run lint",
- "test": "turbo run test"
- }
- }
- ```
-
- ```json
- // DO NOT DO THIS - defeats parallelization
- // Root package.json
- {
- "scripts": {
- "build": "cd apps/web && next build && cd ../api && tsc",
- "lint": "eslint apps/ packages/",
- "test": "vitest"
- }
- }
- ```
-
- 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:**
-
- ```json
- // package.json - ALWAYS "turbo run"
- {
- "scripts": {
- "build": "turbo run build"
- }
- }
- ```
-
- ```yaml
- # CI workflows - ALWAYS "turbo run"
- - run: turbo run build --affected
- ```
-
- **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"
-
- ```
- Configure a task?
- ├─ Define task dependencies → references/configuration/tasks.md
- ├─ Lint/check-types (parallel + caching) → Use Transit Nodes pattern (see below)
- ├─ Specify build outputs → references/configuration/tasks.md#outputs
- ├─ Handle environment variables → references/environment/RULE.md
- ├─ Set up dev/watch tasks → references/configuration/tasks.md#persistent
- ├─ Package-specific config → references/configuration/RULE.md#package-configurations
- └─ Global settings (cacheDir, daemon) → references/configuration/global-options.md
- ```
-
- ### "My cache isn't working"
-
- ```
- Cache problems?
- ├─ Tasks run but outputs not restored → Missing `outputs` key
- ├─ Cache misses unexpectedly → references/caching/gotchas.md
- ├─ Need to debug hash inputs → Use --summarize or --dry
- ├─ Want to skip cache entirely → Use --force or cache: false
- ├─ Remote cache not working → references/caching/remote-cache.md
- └─ Environment causing misses → references/environment/gotchas.md
- ```
-
- ### "I want to run only changed packages"
-
- ```
- Run only what changed?
- ├─ Changed packages + dependents (RECOMMENDED) → turbo run build --affected
- ├─ Custom base branch → --affected --affected-base=origin/develop
- ├─ Manual git comparison → --filter=...[origin/main]
- └─ See all filter options → references/filtering/RULE.md
- ```
-
- **`--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"
-
- ```
- Filter packages?
- ├─ Only changed packages → --affected (see above)
- ├─ By package name → --filter=web
- ├─ By directory → --filter=./apps/*
- ├─ Package + dependencies → --filter=web...
- ├─ Package + dependents → --filter=...web
- └─ Complex combinations → references/filtering/patterns.md
- ```
-
- ### "Environment variables aren't working"
-
- ```
- Environment issues?
- ├─ Vars not available at runtime → Strict mode filtering (default)
- ├─ Cache hits with wrong env → Var not in `env` key
- ├─ .env changes not causing rebuilds → .env not in `inputs`
- ├─ CI variables missing → references/environment/gotchas.md
- └─ Framework vars (NEXT_PUBLIC_*) → Auto-included via inference
- ```
-
- ### "I need to set up CI"
-
- ```
- CI setup?
- ├─ GitHub Actions → references/ci/github-actions.md
- ├─ Vercel deployment → references/ci/vercel.md
- ├─ Remote cache in CI → references/caching/remote-cache.md
- ├─ Only build changed packages → --affected flag
- ├─ Skip unnecessary builds → turbo-ignore (references/cli/commands.md)
- └─ Skip container setup when no changes → turbo-ignore
- ```
-
- ### "I want to watch for changes during development"
-
- ```
- Watch mode?
- ├─ Re-run tasks on change → turbo watch (references/watch/RULE.md)
- ├─ Dev servers with dependencies → Use `with` key (references/configuration/tasks.md#with)
- ├─ Restart dev server on dep change → Use `interruptible: true`
- └─ Persistent dev tasks → Use `persistent: true`
- ```
-
- ### "I need to create/structure a package"
-
- ```
- Package creation/structure?
- ├─ Create an internal package → references/best-practices/packages.md
- ├─ Repository structure → references/best-practices/structure.md
- ├─ Dependency management → references/best-practices/dependencies.md
- ├─ Best practices overview → references/best-practices/RULE.md
- ├─ JIT vs Compiled packages → references/best-practices/packages.md#compilation-strategies
- └─ Sharing code between apps → references/best-practices/RULE.md#package-types
- ```
-
- ### "How should I structure my monorepo?"
-
- ```
- Monorepo structure?
- ├─ Standard layout (apps/, packages/) → references/best-practices/RULE.md
- ├─ Package types (apps vs libraries) → references/best-practices/RULE.md#package-types
- ├─ Creating internal packages → references/best-practices/packages.md
- ├─ TypeScript configuration → references/best-practices/structure.md#typescript-configuration
- ├─ ESLint configuration → references/best-practices/structure.md#eslint-configuration
- ├─ Dependency management → references/best-practices/dependencies.md
- └─ Enforce package boundaries → references/boundaries/RULE.md
- ```
-
- ### "I want to enforce architectural boundaries"
-
- ```
- Enforce boundaries?
- ├─ Check for violations → turbo boundaries
- ├─ Tag packages → references/boundaries/RULE.md#tags
- ├─ Restrict which packages can import others → references/boundaries/RULE.md#rule-types
- └─ Prevent cross-package file imports → references/boundaries/RULE.md
- ```
-
- ## 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.
-
- ```json
- // WRONG - using shorthand in package.json
- {
- "scripts": {
- "build": "turbo build",
- "dev": "turbo dev"
- }
- }
-
- // CORRECT
- {
- "scripts": {
- "build": "turbo run build",
- "dev": "turbo run dev"
- }
- }
- ```
-
- ```yaml
- # WRONG - using shorthand in CI
- - run: turbo build --affected
-
- # CORRECT
- - run: turbo run build --affected
- ```
-
- ### Root Scripts Bypassing Turbo
-
- Root `package.json` scripts MUST delegate to `turbo run`, not run tasks directly.
-
- ```json
- // WRONG - bypasses turbo entirely
- {
- "scripts": {
- "build": "bun build",
- "dev": "bun dev"
- }
- }
-
- // CORRECT - delegates to turbo
- {
- "scripts": {
- "build": "turbo run build",
- "dev": "turbo run dev"
- }
- }
- ```
-
- ### Using `&&` to Chain Turbo Tasks
-
- Don't chain turbo tasks with `&&`. Let turbo orchestrate.
-
- ```json
- // WRONG - turbo task not using turbo run
- {
- "scripts": {
- "changeset:publish": "bun build && changeset publish"
- }
- }
-
- // CORRECT
- {
- "scripts": {
- "changeset:publish": "turbo run build && changeset publish"
- }
- }
- ```
-
- ### `prebuild` Scripts That Manually Build Dependencies
-
- Scripts like `prebuild` that manually build other packages bypass Turborepo's dependency graph.
-
- ```json
- // WRONG - manually building dependencies
- {
- "scripts": {
- "prebuild": "cd ../../packages/types && bun run build && cd ../utils && bun run build",
- "build": "next build"
- }
- }
- ```
-
- **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
-
- ```json
- // CORRECT - declare dependency, let turbo handle build order
- // package.json
- {
- "dependencies": {
- "@repo/types": "workspace:*",
- "@repo/utils": "workspace:*"
- },
- "scripts": {
- "build": "next build"
- }
- }
-
- // turbo.json
- {
- "tasks": {
- "build": {
- "dependsOn": ["^build"]
- }
- }
- }
- ```
-
- **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 via the **global hash** — tasks cannot opt out of specific files, even with negation globs in `inputs`. Be specific.
-
- ```json
- // WRONG - heavy hammer, affects all hashes
- {
- "globalDependencies": ["**/.env.*local"]
- }
-
- // BETTER - move to task-level inputs
- {
- "globalDependencies": [".env"],
- "tasks": {
- "build": {
- "inputs": ["$TURBO_DEFAULT$", ".env*"],
- "outputs": ["dist/**"]
- }
- }
- }
- ```
-
- With `futureFlags.globalConfiguration`, this problem is reduced because `global.inputs` files are folded into each task's inputs (not the global hash). Tasks can exclude specific files:
-
- ```json
- // BEST - global.inputs with per-task exclusion
- {
- "futureFlags": { "globalConfiguration": true },
- "global": {
- "inputs": [".env"]
- },
- "tasks": {
- "build": { "outputs": ["dist/**"] },
- "lint": {
- "inputs": ["$TURBO_DEFAULT$", "!$TURBO_ROOT$/.env"]
- }
- }
- }
- ```
-
- ### Repetitive Task Configuration
-
- Look for repeated configuration across tasks that can be collapsed. Turborepo supports shared configuration patterns.
-
- ```json
- // WRONG - repetitive env and inputs across tasks
- {
- "tasks": {
- "build": {
- "env": ["API_URL", "DATABASE_URL"],
- "inputs": ["$TURBO_DEFAULT$", ".env*"]
- },
- "test": {
- "env": ["API_URL", "DATABASE_URL"],
- "inputs": ["$TURBO_DEFAULT$", ".env*"]
- },
- "dev": {
- "env": ["API_URL", "DATABASE_URL"],
- "inputs": ["$TURBO_DEFAULT$", ".env*"],
- "cache": false,
- "persistent": true
- }
- }
- }
-
- // BETTER - use globalEnv and globalDependencies for shared config
- {
- "globalEnv": ["API_URL", "DATABASE_URL"],
- "globalDependencies": [".env*"],
- "tasks": {
- "build": {},
- "test": {},
- "dev": {
- "cache": false,
- "persistent": true
- }
- }
- }
- ```
-
- **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.
-
- ```bash
- # WRONG - bypasses dependency graph
- turbo run lint --parallel
-
- # CORRECT - configure tasks to allow parallel execution
- # In turbo.json, set dependsOn appropriately (or use transit nodes)
- turbo run lint
- ```
-
- ### 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.
-
- ```json
- // WRONG - root turbo.json with many package-specific overrides
- {
- "tasks": {
- "test": { "dependsOn": ["build"] },
- "@repo/web#test": { "outputs": ["coverage/**"] },
- "@repo/api#test": { "outputs": ["coverage/**"] },
- "@repo/utils#test": { "outputs": [] },
- "@repo/cli#test": { "outputs": [] },
- "@repo/core#test": { "outputs": [] }
- }
- }
-
- // CORRECT - use Package Configurations
- // Root turbo.json - base config only
- {
- "tasks": {
- "test": { "dependsOn": ["build"] }
- }
- }
-
- // packages/web/turbo.json - package-specific override
- {
- "extends": ["//"],
- "tasks": {
- "test": { "outputs": ["coverage/**"] }
- }
- }
-
- // packages/api/turbo.json
- {
- "extends": ["//"],
- "tasks": {
- "test": { "outputs": ["coverage/**"] }
- }
- }
- ```
-
- **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.
-
- ```json
- // WRONG - traversing out of package
- {
- "tasks": {
- "build": {
- "inputs": ["$TURBO_DEFAULT$", "../shared-config.json"]
- }
- }
- }
-
- // CORRECT - use $TURBO_ROOT$ for repo root
- {
- "tasks": {
- "build": {
- "inputs": ["$TURBO_DEFAULT$", "$TURBO_ROOT$/shared-config.json"]
- }
- }
- }
- ```
-
- ### 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
-
- ```json
- // WRONG: build produces files but they're not cached
- {
- "tasks": {
- "build": {
- "dependsOn": ["^build"]
- }
- }
- }
-
- // CORRECT: build outputs are cached
- {
- "tasks": {
- "build": {
- "dependsOn": ["^build"],
- "outputs": ["dist/**"]
- }
- }
- }
- ```
-
- 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:
-
- ```json
- // If tsconfig has incremental: true, tsc --noEmit produces cache files
- {
- "tasks": {
- "typecheck": {
- "outputs": ["node_modules/.cache/tsbuildinfo.json"] // or wherever tsBuildInfoFile points
- }
- }
- }
- ```
-
- 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
-
- ```json
- {
- "tasks": {
- // ^build = run build in DEPENDENCIES first (other packages this one imports)
- "build": {
- "dependsOn": ["^build"]
- },
- // build (no ^) = run build in SAME PACKAGE first
- "test": {
- "dependsOn": ["build"]
- },
- // pkg#task = specific package's task
- "deploy": {
- "dependsOn": ["web#build"]
- }
- }
- }
- ```
-
- ### Environment Variables Not Hashed
-
- ```json
- // WRONG: API_URL changes won't cause rebuilds
- {
- "tasks": {
- "build": {
- "outputs": ["dist/**"]
- }
- }
- }
-
- // CORRECT: API_URL changes invalidate cache
- {
- "tasks": {
- "build": {
- "outputs": ["dist/**"],
- "env": ["API_URL", "API_KEY"]
- }
- }
- }
- ```
-
- ### `.env` Files Not in Inputs
-
- Turbo does NOT load `.env` files - your framework does. But Turbo needs to know about changes:
-
- ```json
- // WRONG: .env changes don't invalidate cache
- {
- "tasks": {
- "build": {
- "env": ["API_URL"]
- }
- }
- }
-
- // CORRECT: .env file changes invalidate cache
- {
- "tasks": {
- "build": {
- "env": ["API_URL"],
- "inputs": ["$TURBO_DEFAULT$", ".env", ".env.*"]
- }
- }
- }
- ```
-
- ### 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.
-
- ```
- // WRONG - root .env affects all packages implicitly
- my-monorepo/
- ├── .env # Which packages use this?
- ├── apps/
- │ ├── web/
- │ └── api/
- └── packages/
-
- // CORRECT - .env files in packages that need them
- my-monorepo/
- ├── apps/
- │ ├── web/
- │ │ └── .env # Clear: web needs DATABASE_URL
- │ └── api/
- │ └── .env # Clear: api needs API_KEY
- └── packages/
- ```
-
- **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:
-
- ```json
- // If CI scripts need GITHUB_TOKEN but it's not in env:
- {
- "globalPassThroughEnv": ["GITHUB_TOKEN", "CI"],
- "tasks": { ... }
- }
- ```
-
- Or use `--env-mode=loose` (not recommended for production).
-
- ### Shared Code in Apps (Should Be a Package)
-
- ```
- // WRONG: Shared code inside an app
- apps/
- web/
- shared/ # This breaks monorepo principles!
- utils.ts
-
- // CORRECT: Extract to a package
- packages/
- utils/
- src/utils.ts
- ```
-
- ### Accessing Files Across Package Boundaries
-
- ```typescript
- // WRONG: Reaching into another package's internals
- import { Button } from "../../packages/ui/src/button";
-
- // CORRECT: Install and import properly
- import { Button } from "@repo/ui/button";
- ```
-
- ### Too Many Root Dependencies
-
- ```json
- // WRONG: App dependencies in root
- {
- "dependencies": {
- "react": "^18",
- "next": "^14"
- }
- }
-
- // CORRECT: Only repo tools in root
- {
- "devDependencies": {
- "turbo": "latest"
- }
- }
- ```
-
- ## Common Task Configurations
-
- ### Standard Build Pipeline
-
- ```json
- {
- "$schema": "https://v2-9-7-canary-14.turborepo.dev/schema.json",
- "tasks": {
- "build": {
- "dependsOn": ["^build"],
- "outputs": ["dist/**", ".next/**", "!.next/cache/**"]
- },
- "dev": {
- "cache": false,
- "persistent": true
- }
- }
- }
- ```
-
- 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**:
-
- ```json
- // Root turbo.json
- {
- "tasks": {
- "dev": {
- "dependsOn": ["^dev"],
- "cache": false,
- "persistent": false // Packages have one-shot dev scripts
- }
- }
- }
-
- // Package turbo.json (apps/web/turbo.json)
- {
- "extends": ["//"],
- "tasks": {
- "dev": {
- "persistent": true // Apps run long-running dev servers
- }
- }
- }
- ```
-
- **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:
-
- ```json
- {
- "tasks": {
- "prepare": {
- "dependsOn": ["^prepare"],
- "outputs": ["dist/**"]
- },
- "dev": {
- "dependsOn": ["prepare"],
- "cache": false,
- "persistent": true
- }
- }
- }
- ```
-
- ### 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):**
+ Build system for JavaScript/TypeScript monorepos. Turborepo caches task outputs and runs tasks in parallel based on the dependency graph.
- - Allows parallel execution (fast)
- - But cache is INCORRECT - changing dependency source won't invalidate cache
+ This SKILL.md is an index. When you need the detail for a topic, **Read the matching `references/<topic>.md` file** — don't work from memory.
- **Transit Nodes solve both:**
+ ## When to use
- ```json
- {
- "tasks": {
- "transit": { "dependsOn": ["^transit"] },
- "my-task": { "dependsOn": ["transit"] }
- }
- }
- ```
+ Use when the user: configures tasks/workflows/pipelines, creates packages, sets up a monorepo, shares code between apps, runs changed/affected packages, debugs the cache, sets up CI, enforces package boundaries, or is working in a repo with `apps/`/`packages/` directories or a `turbo.json`.
- The `transit` task creates dependency relationships without matching any actual script, so tasks run in parallel with correct cache invalidation.
+ ## Two rules that always apply
- **How to identify tasks that need this pattern:** Look for tasks that read source files from dependencies but don't need their build outputs.
+ 1. **Package tasks, not Root Tasks.** Put task logic (scripts) in each package's `package.json`, register the task in root `turbo.json`, and let root `package.json` only delegate via `turbo run <task>`. Root Tasks (`//#taskname`) are a rare exception. See [references/tasks-pipeline.md](./references/tasks-pipeline.md).
+ 2. **`turbo run`, not `turbo`, in code.** Always write `turbo run <task>` in package.json scripts and CI. The bare `turbo <task>` shorthand is only for one-off interactive terminal use. See [references/tasks-pipeline.md](./references/tasks-pipeline.md).
- ### With Environment Variables
+ ## Decision tree → which reference to read
- ```json
- {
- "globalEnv": ["NODE_ENV"],
- "globalDependencies": [".env"],
- "tasks": {
- "build": {
- "dependsOn": ["^build"],
- "outputs": ["dist/**"],
- "env": ["API_URL", "DATABASE_URL"]
- }
- }
- }
```
-
- With `futureFlags.globalConfiguration`, the same config moves global settings under `global` — and `.env` becomes a per-task input instead of a global hash input:
-
- ```json
- {
- "futureFlags": { "globalConfiguration": true },
- "global": {
- "env": ["NODE_ENV"],
- "inputs": [".env"]
- },
- "tasks": {
- "build": {
- "dependsOn": ["^build"],
- "outputs": ["dist/**"],
- "env": ["API_URL", "DATABASE_URL"]
- }
- }
- }
+ What are you doing?
+ ├─ Configuring a task / pipeline (dependsOn, outputs, transit nodes, dev/watch) → tasks-pipeline.md
+ ├─ Cache not working / wrong cache hits / debugging hashes → caching.md
+ ├─ Sharing cache across machines / CI → remote-cache.md
+ ├─ Running only changed packages / --filter / --affected → filtering.md
+ ├─ Setting up CI (GitHub Actions, Vercel, turbo-ignore) → ci.md
+ ├─ Env vars not available / wrong cache from env / .env files → env-vars.md
+ ├─ Creating a package / structuring the monorepo / dependencies → packages.md
+ └─ Enforcing import/architectural boundaries → boundaries.md
```
- ## 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, global key, futureFlags, cacheDir, 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 |
- | [environment/modes.md](./references/environment/modes.md) | Strict vs Loose mode, framework inference |
- | [environment/gotchas.md](./references/environment/gotchas.md) | .env files, CI issues |
-
- ### Filtering
-
- | File | Purpose |
- | ----------------------------------------------------------- | ------------------------ |
- | [filtering/RULE.md](./references/filtering/RULE.md) | --filter syntax overview |
- | [filtering/patterns.md](./references/filtering/patterns.md) | Common filter patterns |
-
- ### CI/CD
-
- | File | Purpose |
- | --------------------------------------------------------- | ------------------------------- |
- | [ci/RULE.md](./references/ci/RULE.md) | General CI principles |
- | [ci/github-actions.md](./references/ci/github-actions.md) | Complete GitHub Actions setup |
- | [ci/vercel.md](./references/ci/vercel.md) | Vercel deployment, turbo-ignore |
- | [ci/patterns.md](./references/ci/patterns.md) | --affected, caching strategies |
-
- ### CLI
-
- | File | Purpose |
- | ----------------------------------------------- | --------------------------------------------- |
- | [cli/RULE.md](./references/cli/RULE.md) | turbo run basics |
- | [cli/commands.md](./references/cli/commands.md) | turbo run flags, turbo-ignore, other commands |
-
- ### Best Practices
-
- | File | Purpose |
- | ----------------------------------------------------------------------------- | --------------------------------------------------------------- |
- | [best-practices/RULE.md](./references/best-practices/RULE.md) | Monorepo best practices overview |
- | [best-practices/structure.md](./references/best-practices/structure.md) | Repository structure, workspace config, TypeScript/ESLint setup |
- | [best-practices/packages.md](./references/best-practices/packages.md) | Creating internal packages, JIT vs Compiled, exports |
- | [best-practices/dependencies.md](./references/best-practices/dependencies.md) | Dependency management, installing, version sync |
+ ## Topic index
- ### Watch Mode
+ | Topic | Read this | Covers |
+ | --- | --- | --- |
+ | Tasks & pipeline | [references/tasks-pipeline.md](./references/tasks-pipeline.md) | Package-vs-Root tasks, `turbo run` rule, `dependsOn`/`^build`, outputs, transit nodes, dev/watch patterns, task anti-patterns |
+ | Caching | [references/caching.md](./references/caching.md) | Hash inputs, missing `outputs`, env/`.env` hashing, `globalDependencies`, debugging misses |
+ | Remote cache | [references/remote-cache.md](./references/remote-cache.md) | Vercel Remote Cache, self-hosted, `turbo login`/`link` |
+ | Filtering & affected | [references/filtering.md](./references/filtering.md) | `--affected`, `--filter` by name/dir/`...`, change-set runs |
+ | CI / CD | [references/ci.md](./references/ci.md) | GitHub Actions, Vercel, `turbo-ignore`, `--affected` in CI, passthrough env |
+ | Env vars | [references/env-vars.md](./references/env-vars.md) | `env`/`globalEnv`/`passThroughEnv`, strict vs loose, root `.env` anti-pattern |
+ | Packages & structure | [references/packages.md](./references/packages.md) | Internal packages, `apps/`/`packages/` layout, deps, JIT vs compiled |
+ | Boundaries | [references/boundaries.md](./references/boundaries.md) | `turbo boundaries`, tags, tag-based import rules |
- | File | Purpose |
- | ------------------------------------------- | ----------------------------------------------- |
- | [watch/RULE.md](./references/watch/RULE.md) | turbo watch, interruptible tasks, dev workflows |
+ ## Deeper reference subtrees
- ### Boundaries (Experimental)
+ The topic files above link into the detailed `references/` subtrees when you need full mechanics:
- | File | Purpose |
- | ----------------------------------------------------- | ----------------------------------------------------- |
- | [boundaries/RULE.md](./references/boundaries/RULE.md) | Enforce package isolation, tag-based dependency rules |
+ - **Configuration** — [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, `global` key, futureFlags, cacheDir, envMode), [configuration/gotchas.md](./references/configuration/gotchas.md).
+ - **Caching** — [caching/RULE.md](./references/caching/RULE.md), [caching/remote-cache.md](./references/caching/remote-cache.md), [caching/gotchas.md](./references/caching/gotchas.md) (`--summarize`, `--dry`).
+ - **Environment** — [environment/RULE.md](./references/environment/RULE.md), [environment/modes.md](./references/environment/modes.md), [environment/gotchas.md](./references/environment/gotchas.md).
+ - **Filtering** — [filtering/RULE.md](./references/filtering/RULE.md), [filtering/patterns.md](./references/filtering/patterns.md).
+ - **CI/CD** — [ci/RULE.md](./references/ci/RULE.md), [ci/github-actions.md](./references/ci/github-actions.md), [ci/vercel.md](./references/ci/vercel.md), [ci/patterns.md](./references/ci/patterns.md).
+ - **CLI** — [cli/RULE.md](./references/cli/RULE.md), [cli/commands.md](./references/cli/commands.md) (`turbo run` flags, `turbo-ignore`, other commands).
+ - **Best practices** — [best-practices/RULE.md](./references/best-practices/RULE.md), [best-practices/structure.md](./references/best-practices/structure.md), [best-practices/packages.md](./references/best-practices/packages.md), [best-practices/dependencies.md](./references/best-practices/dependencies.md).
+ - **Watch mode** — [watch/RULE.md](./references/watch/RULE.md) (`turbo watch`, interruptible tasks, dev workflows).
+ - **Boundaries** — [boundaries/RULE.md](./references/boundaries/RULE.md).
## Source Documentation
- This skill is based on the official Turborepo documentation at:
+ This skill is based on the official Turborepo documentation:
- Source: `apps/docs/content/docs/` in the Turborepo repository
- Live: https://turborepo.dev/docs