turborepo
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseTurborepo 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:
- Add the script to each relevant package's
package.json - Register the task in root
turbo.json - Root only delegates via
package.jsonturbo run <task>
DO NOT put task logic in root . This defeats Turborepo's parallelization.
package.jsonjson
// 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 () are ONLY for tasks that truly cannot exist in packages (rare).
//#taskname请勿创建根级任务。始终创建包级任务。
在创建任务/脚本/流水线时,你必须:
- 将脚本添加到每个相关包的中
package.json - 在根目录的中注册该任务
turbo.json - 根目录仅通过
package.json进行代理turbo run <task>
请勿在根目录中编写任务逻辑。这会破坏Turborepo的并行化能力。
package.jsonjson
// 正确做法:在每个包中添加脚本
// 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"
}
}根级任务()仅适用于确实无法在包中存在的任务(这种情况很少见)。
//#tasknameSecondary Rule: turbo run
vs turbo
turbo runturbo次要规则:turbo run
与 turbo
的区别
turbo runturboAlways use when the command is written into code:
turbo runjson
// package.json - ALWAYS "turbo run"
{
"scripts": {
"build": "turbo run build"
}
}yaml
undefined当命令写入代码时,始终使用:
turbo runjson
// package.json - 务必使用"turbo run"
{
"scripts": {
"build": "turbo run build"
}
}yaml
undefinedCI 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只运行已变更的内容?
├─ 已变更包及其依赖包(推荐)→ 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-ignoreCI搭建?
├─ 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.mdCritical Anti-Patterns
关键反模式
Using turbo
Shorthand in Code
turbo在代码中使用turbo
简写
turboturbo runturbo <task>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 runturbo <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 --affectedWRONG - using shorthand in CI
根目录脚本绕过Turbo
- run: turbo build --affected
根目录脚本必须代理到,而非直接运行任务。
package.jsonturbo runjson
// 错误 - 完全绕过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
脚本
prebuildRoot scripts MUST delegate to , not run tasks directly.
package.jsonturbo runjson
// WRONG - bypasses turbo entirely
{
"scripts": {
"build": "bun build",
"dev": "bun dev"
}
}
// CORRECT - delegates to turbo
{
"scripts": {
"build": "turbo run build",
"dev": "turbo run dev"
}
}像这样手动构建其他包的脚本会绕过Turborepo的依赖图。
prebuildjson
// 错误 - 手动构建依赖
{
"scripts": {
"prebuild": "cd ../../packages/types && bun run build && cd ../utils && bun run build",
"build": "next build"
}
}不过,修复方式取决于是否声明了工作区依赖:
-
如果已声明依赖(例如package.json中的),移除
"@repo/types": "workspace:*"脚本。Turbo的prebuild会自动处理这一点。dependsOn: ["^build"] -
如果未声明依赖,的存在是因为没有依赖关系的话
prebuild不会触发。修复方法是:^build- 在package.json中添加依赖:
"@repo/types": "workspace:*" - 然后移除脚本
prebuild
- 在package.json中添加依赖:
json
// 正确 - 声明依赖,让Turbo处理构建顺序
// package.json
{
"dependencies": {
"@repo/types": "workspace:*",
"@repo/utils": "workspace:*"
},
"scripts": {
"build": "next build"
}
}
// turbo.json
{
"tasks": {
"build": {
"dependsOn": ["^build"]
}
}
}关键要点:仅在列为依赖的包中运行构建。未声明依赖 = 无自动构建顺序。
^buildUsing &&
to Chain Turbo Tasks
&&过于宽泛的globalDependencies
globalDependenciesDon'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"
}
}globalDependenciesjson
// 错误 - 影响所有哈希的重型操作
{
"globalDependencies": ["**/.env.*local"]
}
// 更好 - 移至任务级inputs
{
"globalDependencies": [".env"],
"tasks": {
"build": {
"inputs": ["$TURBO_DEFAULT$", ".env*"],
"outputs": ["dist/**"]
}
}
}prebuild
Scripts That Manually Build Dependencies
prebuild重复的任务配置
Scripts like that manually build other packages bypass Turborepo's dependency graph.
prebuildjson
// 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:
-
If dependencies ARE declared (e.g.,in package.json), remove the
"@repo/types": "workspace:*"script. Turbo'sprebuildhandles this automatically.dependsOn: ["^build"] -
If dependencies are NOT declared, theexists because
prebuildwon't trigger without a dependency relationship. The fix is to:^build- Add the dependency to package.json:
"@repo/types": "workspace:*" - Then remove the script
prebuild
- Add the dependency to package.json:
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: only runs build in packages listed as dependencies. No dependency declaration = no automatic build ordering.
^build寻找可以合并的跨任务重复配置。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
globalDependencies不是反模式:大型env
数组
envglobalDependenciesjson
// 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/**"]
}
}
}大型数组(甚至50+个变量)不是问题。这通常意味着用户彻底声明了构建的环境依赖。不要将此标记为问题。
envRepetitive Task Configuration
使用--parallel
标志
--parallelLook 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- affects ALL tasks, use for truly shared configglobalDependencies - Task-level /
env- use when only specific tasks need itinputs
--paralleldependsOnbash
// 错误 - 绕过依赖图
turbo run lint --parallel
// 正确 - 配置任务以允许并行执行
// 在turbo.json中,正确设置dependsOn(或使用中转节点)
turbo run lintNOT an Anti-Pattern: Large env
Arrays
env根目录turbo.json中的包专属任务覆盖
A large 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.
env当多个包需要不同的任务配置时,使用包配置(每个包中的),而非在根目录中使用覆盖来造成混乱。
turbo.jsonturbo.jsonpackage#taskjson
// 错误 - 根目录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-configurationsUsing --parallel
Flag
--parallel在inputs
中使用../
跳出包目录
inputs../The flag bypasses Turborepo's dependency graph. If tasks need parallel execution, configure correctly instead.
--paralleldependsOnbash
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
outputsturbo run lint --parallel
在标记缺少之前,请检查任务实际生成的内容:
outputs- 查看包的脚本(例如,
"build": "tsc")"test": "vitest" - 确定它是将文件写入磁盘还是仅输出到stdout
- 仅当任务生成应缓存的文件时才标记
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中时,即使不生成JS也会写入文件。在假设无输出之前检查tsconfig:
incremental: truetsc --noEmit.tsbuildinfojson
// 如果tsconfig中incremental: true,tsc --noEmit会生成缓存文件
{
"tasks": {
"typecheck": {
"outputs": ["node_modules/.cache/tsbuildinfo.json"] // 或tsBuildInfoFile指向的位置
}
}
}确定TypeScript任务的正确输出:
- 检查tsconfig中是否启用了或
incrementalcomposite - 检查的自定义缓存位置(默认:与
tsBuildInfoFile同目录或项目根目录)outDir - 如果未启用增量模式,不生成文件
tsc --noEmit
CORRECT - configure tasks to allow parallel execution
^build
与build
的混淆
^buildbuildIn turbo.json, set dependsOn appropriately (or use transit nodes)
—
turbo run lint
undefinedjson
{
"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 ( in each package) instead of cluttering root with overrides.
turbo.jsonturbo.jsonpackage#taskjson
// 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 to inherit + extend arrays
$TURBO_EXTENDS$
When to use in root:
package#task- Single package needs a unique dependency (e.g., )
"deploy": { "dependsOn": ["web#build"] } - Temporary override while migrating
See for full details.
references/configuration/RULE.md#package-configurationsjson
// 错误: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
../inputs.env
文件未在inputs中
.envDon't use relative paths like to reference files outside the package. Use instead.
../$TURBO_ROOT$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不会加载文件 - 你的框架会加载。但Turbo需要知道变更:
.envjson
// 错误:.env变更不会使缓存失效
{
"tasks": {
"build": {
"env": ["API_URL"]
}
}
}
// 正确:.env文件变更会使缓存失效
{
"tasks": {
"build": {
"env": ["API_URL"],
"inputs": ["$TURBO_DEFAULT$", ".env", ".env.*"]
}
}
}Missing outputs
for File-Producing Tasks
outputs单体仓库中的根目录.env
文件
.envBefore flagging missing , check what the task actually produces:
outputs- Read the package's script (e.g., ,
"build": "tsc")"test": "vitest" - Determine if it writes files to disk or only outputs to stdout
- 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: or custom
["dist/**"]outDir
TypeScript can still produce cache files:
--noEmitWhen in tsconfig.json, writes files even without emitting JS. Check the tsconfig before assuming no outputs:
incremental: truetsc --noEmit.tsbuildinfojson
// 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:
- Check if or
incrementalis enabled in tsconfigcomposite - Check for custom cache location (default: alongside
tsBuildInfoFileor in project root)outDir - If no incremental mode, produces no files
tsc --noEmit
仓库根目录的文件是反模式 - 即使是小型单体仓库或启动模板也不应该使用。它会在包之间创建隐式耦合,并且不清楚哪些包依赖哪些变量。
.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
^buildbuildCI变量的严格模式过滤
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会过滤环境变量,仅保留/中的变量。CI变量可能缺失:
envglobalEnvjson
// 如果CI脚本需要GITHUB_TOKEN但它不在env中:
{
"globalPassThroughEnv": ["GITHUB_TOKEN", "CI"],
"tasks": { ... }
}或者使用(不推荐用于生产环境)。
--env-mode=looseEnvironment 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
.env跨包边界访问文件
Turbo does NOT load files - your framework does. But Turbo needs to know about changes:
.envjson
// 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
.env过多的根目录依赖
A 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.
.env// 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 to be explicit about what's shared, and document why.
globalEnvjson
// 错误:应用依赖在根目录
{
"dependencies": {
"react": "^18",
"next": "^14"
}
}
// 正确:根目录仅包含仓库工具
{
"devDependencies": {
"turbo": "latest"
}
}Strict Mode Filtering CI Variables
常见任务配置
—
标准构建流水线
By default, Turborepo filters environment variables to only those in /. CI variables may be missing:
envglobalEnvjson
// If CI scripts need GITHUB_TOKEN but it's not in env:
{
"globalPassThroughEnv": ["GITHUB_TOKEN", "CI"],
"tasks": { ... }
}Or use (not recommended for production).
--env-mode=loosejson
{
"$schema": "https://turborepo.dev/schema.v2.json",
"tasks": {
"build": {
"dependsOn": ["^build"],
"outputs": ["dist/**", ".next/**", "!.next/cache/**"]
},
"dev": {
"cache": false,
"persistent": true
}
}
}如果有需要并行执行且缓存失效的任务,添加任务(见下文)。
transitShared Code in Apps (Should Be a Package)
带^dev
模式的开发任务(用于turbo watch
)
^devturbo 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: falsedevturbo watchjson
// 根目录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" - 应用覆盖为以运行实际的开发服务器(Next.js等)
persistent: true - ****在源文件变更时重新运行包的一次性
turbo watch脚本,保持类型同步dev
**预期用法:**运行(而非)。监听模式会在文件变更时重新执行一次性任务,同时保持持久化任务运行。
turbo watch devturbo run dev**替代模式:**使用单独的任务名称如或用于一次性依赖构建,使意图更清晰:
preparegeneratejson
{
"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 task if you have tasks that need parallel execution with cache invalidation (see below).
transit| 文件 | 用途 |
|---|---|
| configuration/RULE.md | turbo.json概述、包配置 |
| configuration/tasks.md | dependsOn、outputs、inputs、env、cache、persistent |
| configuration/global-options.md | globalEnv、globalDependencies、cacheDir、daemon、envMode |
| configuration/gotchas.md | 常见配置错误 |
Dev Task with ^dev
Pattern (for turbo watch
)
^devturbo watch缓存
A task with and in root turbo.json may look unusual but is correct for workflows:
devdependsOn: ["^dev"]persistent: falseturbo watchjson
// 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) have@acme/validators— one-shot type generation that completes quickly"dev": "tsc" - Apps override with for actual dev servers (Next.js, etc.)
persistent: true - re-runs the one-shot package
turbo watchscripts when source files change, keeping types in syncdev
Intended usage: Run (not ). Watch mode re-executes one-shot tasks on file changes while keeping persistent tasks running.
turbo watch devturbo run devAlternative pattern: Use a separate task name like or for one-shot dependency builds to make the intent clearer:
preparegeneratejson
{
"tasks": {
"prepare": {
"dependsOn": ["^prepare"],
"outputs": ["dist/**"]
},
"dev": {
"dependsOn": ["prepare"],
"cache": false,
"persistent": true
}
}
}| File | 用途 |
|---|---|
| caching/RULE.md | 缓存工作原理、哈希输入 |
| caching/remote-cache.md | Vercel远程缓存、自托管、登录/链接 |
| 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 (no dependencies):
dependsOn: []- 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 task creates dependency relationships without matching any actual script, so tasks run in parallel with correct cache invalidation.
transitHow 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.md | env、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
—
| File | Purpose |
|---|---|
| configuration/RULE.md | turbo.json overview, Package Configurations |
| configuration/tasks.md | dependsOn, outputs, inputs, env, cache, persistent |
| configuration/global-options.md | globalEnv, globalDependencies, cacheDir, daemon, envMode |
| configuration/gotchas.md | Common configuration mistakes |
| File | 用途 |
|---|---|
| ci/RULE.md | 通用CI原则 |
| ci/github-actions.md | 完整GitHub Actions设置 |
| ci/vercel.md | Vercel部署、turbo-ignore |
| ci/patterns.md | --affected、缓存策略 |
Caching
CLI
| File | Purpose |
|---|---|
| caching/RULE.md | How caching works, hash inputs |
| caching/remote-cache.md | Vercel Remote Cache, self-hosted, login/link |
| caching/gotchas.md | Debugging cache misses, --summarize, --dry |
| File | 用途 |
|---|---|
| cli/RULE.md | turbo run基础用法 |
| cli/commands.md | turbo run标志、turbo-ignore、其他命令 |
Environment Variables
最佳实践
| File | Purpose |
|---|---|
| environment/RULE.md | env, globalEnv, passThroughEnv |
| environment/modes.md | Strict 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
监听模式
| File | Purpose |
|---|---|
| filtering/RULE.md | --filter syntax overview |
| filtering/patterns.md | Common filter patterns |
| File | 用途 |
|---|---|
| watch/RULE.md | turbo watch、可中断任务、开发工作流 |
CI/CD
边界管控(实验性)
| File | Purpose |
|---|---|
| ci/RULE.md | General CI principles |
| ci/github-actions.md | Complete GitHub Actions setup |
| ci/vercel.md | Vercel deployment, turbo-ignore |
| ci/patterns.md | --affected, caching strategies |
| File | 用途 |
|---|---|
| boundaries/RULE.md | 强制包隔离、基于标签的依赖规则 |
CLI
来源文档
| File | Purpose |
|---|---|
| cli/RULE.md | turbo run basics |
| cli/commands.md | turbo run flags, turbo-ignore, other commands |
本指南基于官方Turborepo文档:
- 源码:Turborepo仓库中的
docs/site/content/docs/ - 在线文档:https://turborepo.dev/docs
Best Practices
—
| File | Purpose |
|---|---|
| best-practices/RULE.md | Monorepo best practices overview |
| best-practices/structure.md | Repository structure, workspace config, TypeScript/ESLint setup |
| best-practices/packages.md | Creating internal packages, JIT vs Compiled, exports |
| best-practices/dependencies.md | Dependency management, installing, version sync |
—
Watch Mode
—
| File | Purpose |
|---|---|
| watch/RULE.md | turbo watch, interruptible tasks, dev workflows |
—
Boundaries (Experimental)
—
| File | Purpose |
|---|---|
| boundaries/RULE.md | Enforce package isolation, tag-based dependency rules |
—
Source Documentation
—
This skill is based on the official Turborepo documentation at:
- Source: in the Turborepo repository
apps/docs/content/docs/ - Live: https://turborepo.dev/docs
—