turborepo

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Turborepo Skill

Turborepo 使用指南

Build system for JavaScript/TypeScript monorepos. Turborepo caches task outputs and runs tasks in parallel based on dependency graph.
面向JavaScript/TypeScript单体仓库(monorepo)的构建系统。Turborepo会缓存任务输出,并基于依赖图并行运行任务。

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).
请勿创建根级任务。始终创建包级任务。
在创建任务/脚本/流水线时,你必须:
  1. 将脚本添加到每个相关包的
    package.json
  2. 在根目录的
    turbo.json
    中注册该任务
  3. 根目录
    package.json
    仅通过
    turbo run <task>
    进行代理
请勿在根目录
package.json
中编写任务逻辑。这会破坏Turborepo的并行化能力。
json
// 正确做法:在每个包中添加脚本
// 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 - 注册任务
{
  "tasks": {
    "build": { "dependsOn": ["^build"], "outputs": ["dist/**"] },
    "lint": {},
    "test": { "dependsOn": ["build"] }
  }
}
json
// 根目录package.json - 仅做代理,无任务逻辑
{
  "scripts": {
    "build": "turbo run build",
    "lint": "turbo run lint",
    "test": "turbo run test"
  }
}
json
// 错误做法:破坏并行化能力
// 根目录package.json
{
  "scripts": {
    "build": "cd apps/web && next build && cd ../api && tsc",
    "lint": "eslint apps/ packages/",
    "test": "vitest"
  }
}
根级任务(
//#taskname
)仅适用于确实无法在包中存在的任务(这种情况很少见)。

Secondary Rule:
turbo run
vs
turbo

次要规则:
turbo run
turbo
的区别

Always use
turbo run
when the command is written into code:
json
// package.json - ALWAYS "turbo run"
{
  "scripts": {
    "build": "turbo run build"
  }
}
yaml
undefined
当命令写入代码时,始终使用
turbo run
json
// package.json - 务必使用"turbo run"
{
  "scripts": {
    "build": "turbo run build"
  }
}
yaml
undefined

CI workflows - ALWAYS "turbo run"

CI工作流 - 务必使用"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.
  • run: turbo run build --affected

**简写形式`turbo <tasks>`仅适用于人类或Agent直接输入的一次性终端命令。切勿在package.json、CI或脚本中写入`turbo build`。**

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
配置任务?
├─ 定义任务依赖 → references/configuration/tasks.md
├─ 代码检查/类型检查(并行+缓存)→ 使用中转节点模式(见下文)
├─ 指定构建输出 → references/configuration/tasks.md#outputs
├─ 处理环境变量 → references/environment/RULE.md
├─ 设置开发/监听任务 → references/configuration/tasks.md#persistent
├─ 包专属配置 → references/configuration/RULE.md#package-configurations
└─ 全局设置(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
缓存问题?
├─ 任务运行但输出未恢复 → 缺少`outputs`键
├─ 缓存意外未命中 → references/caching/gotchas.md
├─ 需要调试哈希输入 → 使用--summarize或--dry
├─ 想要完全跳过缓存 → 使用--force或cache: false
├─ 远程缓存不工作 → references/caching/remote-cache.md
└─ 环境导致缓存未命中 → 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.
只运行已变更的内容?
├─ 已变更包及其依赖包(推荐)→ turbo run build --affected
├─ 自定义基准分支 → --affected --affected-base=origin/develop
├─ 手动Git对比 → --filter=...[origin/main]
└─ 查看所有过滤选项 → references/filtering/RULE.md
**
--affected
是仅运行已变更包的主要方式。**它会自动与默认分支对比,并包含依赖包。

"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
过滤包?
├─ 仅已变更包 → --affected(见上文)
├─ 按包名 → --filter=web
├─ 按目录 → --filter=./apps/*
├─ 包及其依赖 → --filter=web...
├─ 包及其依赖者 → --filter=...web
└─ 复杂组合 → 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
环境问题?
├─ 运行时无法获取变量 → 严格模式过滤(默认)
├─ 环境错误但缓存命中 → 变量未在`env`键中
├─ .env变更未触发重建 → .env未在`inputs`中
├─ CI变量缺失 → references/environment/gotchas.md
└─ 框架变量(NEXT_PUBLIC_*)→ 通过自动推断包含

"I need to set up CI"

"我需要搭建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
CI搭建?
├─ GitHub Actions → references/ci/github-actions.md
├─ Vercel部署 → references/ci/vercel.md
├─ CI中的远程缓存 → references/caching/remote-cache.md
├─ 仅构建已变更包 → --affected标志
├─ 跳过不必要的构建 → turbo-ignore(references/cli/commands.md)
└─ 无变更时跳过容器设置 → 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`
监听模式?
├─ 变更时重新运行任务 → turbo watch(references/watch/RULE.md)
├─ 带依赖的开发服务器 → 使用`with`键(references/configuration/tasks.md#with)
├─ 依赖变更时重启开发服务器 → 使用`interruptible: true`
└─ 持久化开发任务 → 使用`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
包创建/结构化?
├─ 创建内部包 → references/best-practices/packages.md
├─ 仓库结构 → references/best-practices/structure.md
├─ 依赖管理 → references/best-practices/dependencies.md
├─ 最佳实践概述 → references/best-practices/RULE.md
├─ JIT与编译型包 → references/best-practices/packages.md#compilation-strategies
└─ 应用间共享代码 → 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
单体仓库结构?
├─ 标准布局(apps/, packages/)→ references/best-practices/RULE.md
├─ 包类型(应用 vs 库)→ references/best-practices/RULE.md#package-types
├─ 创建内部包 → references/best-practices/packages.md
├─ TypeScript配置 → references/best-practices/structure.md#typescript-configuration
├─ ESLint配置 → references/best-practices/structure.md#eslint-configuration
├─ 依赖管理 → references/best-practices/dependencies.md
└─ 强制包边界 → 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
强制边界?
├─ 检查违规 → turbo boundaries
├─ 标记包 → references/boundaries/RULE.md#tags
├─ 限制包的导入权限 → references/boundaries/RULE.md#rule-types
└─ 禁止跨包文件导入 → references/boundaries/RULE.md

Critical Anti-Patterns

关键反模式

Using
turbo
Shorthand in Code

在代码中使用
turbo
简写

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
undefined
**在package.json脚本和CI流水线中推荐使用
turbo run
。**简写形式
turbo <task>
仅用于交互式终端操作。
json
// 错误 - 在package.json中使用简写
{
  "scripts": {
    "build": "turbo build",
    "dev": "turbo dev"
  }
}

// 正确
{
  "scripts": {
    "build": "turbo run build",
    "dev": "turbo run dev"
  }
}
yaml
// 错误 - 在CI中使用简写
- run: turbo build --affected

// 正确
- run: turbo run build --affected

WRONG - using shorthand in CI

根目录脚本绕过Turbo

  • run: turbo build --affected
根目录
package.json
脚本必须代理到
turbo run
,而非直接运行任务。
json
// 错误 - 完全绕过turbo
{
  "scripts": {
    "build": "bun build",
    "dev": "bun dev"
  }
}

// 正确 - 代理到turbo
{
  "scripts": {
    "build": "turbo run build",
    "dev": "turbo run dev"
  }
}

CORRECT

使用
&&
链式调用Turbo任务

  • run: turbo run build --affected
undefined
不要使用
&&
链式调用Turbo任务。让Turbo来协调任务。
json
// 错误 - Turbo任务未使用turbo run
{
  "scripts": {
    "changeset:publish": "bun build && changeset publish"
  }
}

// 正确
{
  "scripts": {
    "changeset:publish": "turbo run build && changeset publish"
  }
}

Root Scripts Bypassing Turbo

手动构建依赖的
prebuild
脚本

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"
  }
}
prebuild
这样手动构建其他包的脚本会绕过Turborepo的依赖图。
json
// 错误 - 手动构建依赖
{
  "scripts": {
    "prebuild": "cd ../../packages/types && bun run build && cd ../utils && bun run build",
    "build": "next build"
  }
}
不过,修复方式取决于是否声明了工作区依赖:
  1. 如果已声明依赖(例如package.json中的
    "@repo/types": "workspace:*"
    ),移除
    prebuild
    脚本。Turbo的
    dependsOn: ["^build"]
    会自动处理这一点。
  2. 如果未声明依赖
    prebuild
    的存在是因为没有依赖关系的话
    ^build
    不会触发。修复方法是:
    • 在package.json中添加依赖:
      "@repo/types": "workspace:*"
    • 然后移除
      prebuild
      脚本
json
// 正确 - 声明依赖,让Turbo处理构建顺序
// package.json
{
  "dependencies": {
    "@repo/types": "workspace:*",
    "@repo/utils": "workspace:*"
  },
  "scripts": {
    "build": "next build"
  }
}

// turbo.json
{
  "tasks": {
    "build": {
      "dependsOn": ["^build"]
    }
  }
}
关键要点:
^build
仅在列为依赖的包中运行构建。未声明依赖 = 无自动构建顺序。

Using
&&
to Chain Turbo Tasks

过于宽泛的
globalDependencies

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"
  }
}
globalDependencies
会影响所有包中的所有任务。请保持具体。
json
// 错误 - 影响所有哈希的重型操作
{
  "globalDependencies": ["**/.env.*local"]
}

// 更好 - 移至任务级inputs
{
  "globalDependencies": [".env"],
  "tasks": {
    "build": {
      "inputs": ["$TURBO_DEFAULT$", ".env*"],
      "outputs": ["dist/**"]
    }
  }
}

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.
寻找可以合并的跨任务重复配置。Turborepo支持共享配置模式。
json
// 错误 - 跨任务重复env和inputs
{
  "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
    }
  }
}

// 更好 - 使用globalEnv和globalDependencies共享配置
{
  "globalEnv": ["API_URL", "DATABASE_URL"],
  "globalDependencies": [".env*"],
  "tasks": {
    "build": {},
    "test": {},
    "dev": {
      "cache": false,
      "persistent": true
    }
  }
}
何时使用全局 vs 任务级配置:
  • globalEnv
    /
    globalDependencies
    - 影响所有任务,用于真正共享的配置
  • 任务级
    env
    /
    inputs
    - 仅当特定任务需要时使用

Overly Broad
globalDependencies

不是反模式:大型
env
数组

globalDependencies
affects ALL tasks in ALL packages. 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/**"]
    }
  }
}
大型
env
数组(甚至50+个变量)不是问题。这通常意味着用户彻底声明了构建的环境依赖。不要将此标记为问题。

Repetitive Task Configuration

使用
--parallel
标志

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
--parallel
标志会绕过Turborepo的依赖图。如果任务需要并行执行,请正确配置
dependsOn
bash
// 错误 - 绕过依赖图
turbo run lint --parallel

// 正确 - 配置任务以允许并行执行
// 在turbo.json中,正确设置dependsOn(或使用中转节点)
turbo run lint

NOT an Anti-Pattern: Large
env
Arrays

根目录turbo.json中的包专属任务覆盖

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.
当多个包需要不同的任务配置时,使用包配置(每个包中的
turbo.json
),而非在根目录
turbo.json
中使用
package#task
覆盖来造成混乱。
json
// 错误 - 根目录turbo.json包含大量包专属覆盖
{
  "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": [] }
  }
}

// 正确 - 使用包配置
// 根目录turbo.json - 仅基础配置
{
  "tasks": {
    "test": { "dependsOn": ["build"] }
  }
}

// packages/web/turbo.json - 包专属覆盖
{
  "extends": ["//"],
  "tasks": {
    "test": { "outputs": ["coverage/**"] }
  }
}

// packages/api/turbo.json
{
  "extends": ["//"],
  "tasks": {
    "test": { "outputs": ["coverage/**"] }
  }
}
包配置的优势:
  • 配置与影响的代码靠近
  • 根目录turbo.json保持简洁,专注于基础模式
  • 更容易理解每个包的特殊之处
  • 支持
    $TURBO_EXTENDS$
    来继承并扩展数组
何时在根目录使用
package#task
  • 单个包需要独特的依赖(例如
    "deploy": { "dependsOn": ["web#build"] }
  • 迁移期间的临时覆盖
详见
references/configuration/RULE.md#package-configurations
获取完整详情。

Using
--parallel
Flag

inputs
中使用
../
跳出包目录

The
--parallel
flag bypasses Turborepo's dependency graph. If tasks need parallel execution, configure
dependsOn
correctly instead.
bash
undefined
不要使用
../
这样的相对路径引用包外的文件。请使用
$TURBO_ROOT$
替代。
json
// 错误 - 跳出包目录
{
  "tasks": {
    "build": {
      "inputs": ["$TURBO_DEFAULT$", "../shared-config.json"]
    }
  }
}

// 正确 - 使用$TURBO_ROOT$指向仓库根目录
{
  "tasks": {
    "build": {
      "inputs": ["$TURBO_DEFAULT$", "$TURBO_ROOT$/shared-config.json"]
    }
  }
}

WRONG - bypasses dependency graph

生成文件的任务缺少
outputs

turbo run lint --parallel
在标记缺少
outputs
之前,请检查任务实际生成的内容:
  1. 查看包的脚本(例如
    "build": "tsc"
    ,
    "test": "vitest"
  2. 确定它是将文件写入磁盘还是仅输出到stdout
  3. 仅当任务生成应缓存的文件时才标记
json
// 错误:构建生成文件但未缓存
{
  "tasks": {
    "build": {
      "dependsOn": ["^build"]
    }
  }
}

// 正确:构建输出被缓存
{
  "tasks": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": ["dist/**"]
    }
  }
}
各框架的常见输出:
  • Next.js:
    [".next/**", "!.next/cache/**"]
  • Vite/Rollup:
    ["dist/**"]
  • tsc:
    ["dist/**"]
    或自定义
    outDir
TypeScript
--noEmit
仍可能生成缓存文件:
当tsconfig.json中
incremental: true
时,
tsc --noEmit
即使不生成JS也会写入
.tsbuildinfo
文件。在假设无输出之前检查tsconfig:
json
// 如果tsconfig中incremental: true,tsc --noEmit会生成缓存文件
{
  "tasks": {
    "typecheck": {
      "outputs": ["node_modules/.cache/tsbuildinfo.json"] // 或tsBuildInfoFile指向的位置
    }
  }
}
确定TypeScript任务的正确输出:
  1. 检查tsconfig中是否启用了
    incremental
    composite
  2. 检查
    tsBuildInfoFile
    的自定义缓存位置(默认:与
    outDir
    同目录或项目根目录)
  3. 如果未启用增量模式,
    tsc --noEmit
    不生成文件

CORRECT - configure tasks to allow parallel execution

^build
build
的混淆

In turbo.json, set dependsOn appropriately (or use transit nodes)

turbo run lint
undefined
json
{
  "tasks": {
    // ^build = 先在依赖包中运行build(当前包导入的其他包)
    "build": {
      "dependsOn": ["^build"]
    },
    // build(无^)= 先在当前包中运行build
    "test": {
      "dependsOn": ["build"]
    },
    // pkg#task = 指定包的任务
    "deploy": {
      "dependsOn": ["web#build"]
    }
  }
}

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.
json
// 错误:API_URL变更不会触发重建
{
  "tasks": {
    "build": {
      "outputs": ["dist/**"]
    }
  }
}

// 正确:API_URL变更会使缓存失效
{
  "tasks": {
    "build": {
      "outputs": ["dist/**"],
      "env": ["API_URL", "API_KEY"]
    }
  }
}

Using
../
to Traverse Out of Package in
inputs

.env
文件未在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"]
    }
  }
}
Turbo不会加载
.env
文件 - 你的框架会加载。但Turbo需要知道变更:
json
// 错误:.env变更不会使缓存失效
{
  "tasks": {
    "build": {
      "env": ["API_URL"]
    }
  }
}

// 正确:.env文件变更会使缓存失效
{
  "tasks": {
    "build": {
      "env": ["API_URL"],
      "inputs": ["$TURBO_DEFAULT$", ".env", ".env.*"]
    }
  }
}

Missing
outputs
for File-Producing Tasks

单体仓库中的根目录
.env
文件

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
仓库根目录的
.env
文件是反模式 - 即使是小型单体仓库或启动模板也不应该使用。它会在包之间创建隐式耦合,并且不清楚哪些包依赖哪些变量。
// 错误 - 根目录.env隐式影响所有包
my-monorepo/
├── .env              # 哪些包使用这个?
├── apps/
│   ├── web/
│   └── api/
└── packages/

// 正确 - .env文件放在需要它们的包中
my-monorepo/
├── apps/
│   ├── web/
│   │   └── .env      # 明确:web需要DATABASE_URL
│   └── api/
│       └── .env      # 明确:api需要API_KEY
└── packages/
根目录
.env
的问题:
  • 不清楚哪些包使用哪些变量
  • 所有包都会获取所有变量(即使它们不需要)
  • 缓存失效粒度粗(根目录.env变更会使所有内容失效)
  • 安全风险:包可能意外访问为其他包准备的敏感变量
  • 坏习惯从小事开始 - 启动模板应该示范正确的模式
如果必须共享变量,使用
globalEnv
明确说明共享的内容,并记录原因。

^build
vs
build
Confusion

CI变量的严格模式过滤

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"]
    }
  }
}
默认情况下,Turbo会过滤环境变量,仅保留
env
/
globalEnv
中的变量。CI变量可能缺失:
json
// 如果CI脚本需要GITHUB_TOKEN但它不在env中:
{
  "globalPassThroughEnv": ["GITHUB_TOKEN", "CI"],
  "tasks": { ... }
}
或者使用
--env-mode=loose
(不推荐用于生产环境)。

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"]
    }
  }
}
// 错误:共享代码在应用内部
apps/
  web/
    shared/          # 这违反了单体仓库原则!
      utils.ts

// 正确:提取为包
packages/
  utils/
    src/utils.ts

.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.*"]
    }
  }
}
typescript
// 错误:访问另一个包的内部实现
import { Button } from "../../packages/ui/src/button";

// 正确:正确安装并导入
import { Button } from "@repo/ui/button";

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.
json
// 错误:应用依赖在根目录
{
  "dependencies": {
    "react": "^18",
    "next": "^14"
  }
}

// 正确:根目录仅包含仓库工具
{
  "devDependencies": {
    "turbo": "latest"
  }
}

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).
json
{
  "$schema": "https://turborepo.dev/schema.v2.json",
  "tasks": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": ["dist/**", ".next/**", "!.next/cache/**"]
    },
    "dev": {
      "cache": false,
      "persistent": true
    }
  }
}
如果有需要并行执行且缓存失效的任务,添加
transit
任务(见下文)。

Shared Code in Apps (Should Be a Package)

^dev
模式的开发任务(用于
turbo watch

// 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
根目录turbo.json中
dependsOn: ["^dev"]
persistent: false
dev
任务可能看起来不寻常,但对于
turbo watch
工作流是正确的
json
// 根目录turbo.json
{
  "tasks": {
    "dev": {
      "dependsOn": ["^dev"],
      "cache": false,
      "persistent": false  // 包使用一次性开发脚本
    }
  }
}

// 包turbo.json (apps/web/turbo.json)
{
  "extends": ["//"],
  "tasks": {
    "dev": {
      "persistent": true  // 应用运行长期的开发服务器
    }
  }
}
为什么这样有效:
  • (例如
    @acme/db
    ,
    @acme/validators
    )有
    "dev": "tsc"
    — 快速完成的一次性类型生成
  • 应用覆盖为
    persistent: true
    以运行实际的开发服务器(Next.js等)
  • **
    turbo watch
    **在源文件变更时重新运行包的一次性
    dev
    脚本,保持类型同步
**预期用法:**运行
turbo watch dev
(而非
turbo run dev
)。监听模式会在文件变更时重新执行一次性任务,同时保持持久化任务运行。
**替代模式:**使用单独的任务名称如
prepare
generate
用于一次性依赖构建,使意图更清晰:
json
{
  "tasks": {
    "prepare": {
      "dependsOn": ["^prepare"],
      "outputs": ["dist/**"]
    },
    "dev": {
      "dependsOn": ["prepare"],
      "cache": false,
      "persistent": true
    }
  }
}

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";
有些任务可以并行执行(不需要依赖的构建输出)但必须在依赖源代码变更时使缓存失效。
dependsOn: ["^taskname"]
的问题:
  • 强制顺序执行(慢)
dependsOn: []
(无依赖)的问题:
  • 允许并行执行(快)
  • 但缓存不正确 - 依赖源代码变更不会使缓存失效
中转节点解决了这两个问题:
json
{
  "tasks": {
    "transit": { "dependsOn": ["^transit"] },
    "my-task": { "dependsOn": ["transit"] }
  }
}
transit
任务创建了依赖关系但不匹配任何实际脚本,因此任务可以并行运行且缓存失效正确。
**如何识别需要此模式的任务:**寻找读取依赖源代码但不需要其构建输出的任务。

Too Many Root Dependencies

带环境变量的配置

json
// WRONG: App dependencies in root
{
  "dependencies": {
    "react": "^18",
    "next": "^14"
  }
}

// CORRECT: Only repo tools in root
{
  "devDependencies": {
    "turbo": "latest"
  }
}
json
{
  "globalEnv": ["NODE_ENV"],
  "globalDependencies": [".env"],
  "tasks": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": ["dist/**"],
      "env": ["API_URL", "DATABASE_URL"]
    }
  }
}

Common Task Configurations

参考索引

Standard Build Pipeline

配置

json
{
  "$schema": "https://turborepo.dev/schema.v2.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).
文件用途
configuration/RULE.mdturbo.json概述、包配置
configuration/tasks.mddependsOn、outputs、inputs、env、cache、persistent
configuration/global-options.mdglobalEnv、globalDependencies、cacheDir、daemon、envMode
configuration/gotchas.md常见配置错误

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
    }
  }
}
File用途
caching/RULE.md缓存工作原理、哈希输入
caching/remote-cache.mdVercel远程缓存、自托管、登录/链接
caching/gotchas.md调试缓存未命中、--summarize、--dry

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:
json
{
  "tasks": {
    "transit": { "dependsOn": ["^transit"] },
    "my-task": { "dependsOn": ["transit"] }
  }
}
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.
File用途
environment/RULE.mdenv、globalEnv、passThroughEnv
environment/modes.md严格模式 vs 宽松模式、框架自动推断
environment/gotchas.md.env文件、CI问题

With Environment Variables

过滤

json
{
  "globalEnv": ["NODE_ENV"],
  "globalDependencies": [".env"],
  "tasks": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": ["dist/**"],
      "env": ["API_URL", "DATABASE_URL"]
    }
  }
}
File用途
filtering/RULE.md--filter语法概述
filtering/patterns.md常见过滤模式

Reference Index

CI/CD

Configuration

FilePurpose
configuration/RULE.mdturbo.json overview, Package Configurations
configuration/tasks.mddependsOn, outputs, inputs, env, cache, persistent
configuration/global-options.mdglobalEnv, globalDependencies, cacheDir, daemon, envMode
configuration/gotchas.mdCommon configuration mistakes
File用途
ci/RULE.md通用CI原则
ci/github-actions.md完整GitHub Actions设置
ci/vercel.mdVercel部署、turbo-ignore
ci/patterns.md--affected、缓存策略

Caching

CLI

FilePurpose
caching/RULE.mdHow caching works, hash inputs
caching/remote-cache.mdVercel Remote Cache, self-hosted, login/link
caching/gotchas.mdDebugging cache misses, --summarize, --dry
File用途
cli/RULE.mdturbo run基础用法
cli/commands.mdturbo run标志、turbo-ignore、其他命令

Environment Variables

最佳实践

FilePurpose
environment/RULE.mdenv, globalEnv, passThroughEnv
environment/modes.mdStrict vs Loose mode, framework inference
environment/gotchas.md.env files, CI issues
File用途
best-practices/RULE.md单体仓库最佳实践概述
best-practices/structure.md仓库结构、工作区配置、TypeScript/ESLint设置
best-practices/packages.md创建内部包、JIT vs 编译型、导出
best-practices/dependencies.md依赖管理、安装、版本同步

Filtering

监听模式

FilePurpose
filtering/RULE.md--filter syntax overview
filtering/patterns.mdCommon filter patterns
File用途
watch/RULE.mdturbo watch、可中断任务、开发工作流

CI/CD

边界管控(实验性)

FilePurpose
ci/RULE.mdGeneral CI principles
ci/github-actions.mdComplete GitHub Actions setup
ci/vercel.mdVercel deployment, turbo-ignore
ci/patterns.md--affected, caching strategies
File用途
boundaries/RULE.md强制包隔离、基于标签的依赖规则

CLI

来源文档

FilePurpose
cli/RULE.mdturbo run basics
cli/commands.mdturbo run flags, turbo-ignore, other commands
本指南基于官方Turborepo文档:

Best Practices

FilePurpose
best-practices/RULE.mdMonorepo best practices overview
best-practices/structure.mdRepository structure, workspace config, TypeScript/ESLint setup
best-practices/packages.mdCreating internal packages, JIT vs Compiled, exports
best-practices/dependencies.mdDependency management, installing, version sync

Watch Mode

FilePurpose
watch/RULE.mdturbo watch, interruptible tasks, dev workflows

Boundaries (Experimental)

FilePurpose
boundaries/RULE.mdEnforce package isolation, tag-based dependency rules

Source Documentation

This skill is based on the official Turborepo documentation at: