turborepo

turborepo

熱門

Turborepo Monorepo 建置系統指南。觸發條件包含:turbo.json、任務管線 (task pipelines)、dependsOn、快取、遠端快取、"turbo" CLI、--filter、--affected、CI 最佳化、環境變數、內部套件、Monorepo 架構/最佳做法,以及套件邊界約束。 適用於使用者需要:設定任務/工作流程/管線 (pipelines)、建立套件、架設 Monorepo、在各應用程式 (apps) 間共用程式碼、執行受變更/受影響的套件、除錯與排查快取問題,或是專案包含 apps/packages 目錄時。

3.1萬星標
2380分支
更新於 2026/6/10
SKILL.md
唯讀
名稱
turborepo
描述

Turborepo Monorepo 建置系統指南。觸發條件包含:turbo.json、任務管線 (task pipelines)、dependsOn、快取、遠端快取、"turbo" CLI、--filter、--affected、CI 最佳化、環境變數、內部套件、Monorepo 架構/最佳做法,以及套件邊界約束。 適用於使用者需要:設定任務/工作流程/管線 (pipelines)、建立套件、架設 Monorepo、在各應用程式 (apps) 間共用程式碼、執行受變更/受影響的套件、除錯與排查快取問題,或是專案包含 apps/packages 目錄時。

Turborepo Skill

適用於 JavaScript/TypeScript Monorepo 的建置系統。Turborepo 能快取任務輸出產物,並根據相依性圖表 (dependency graph) 平行執行任務。

重要原則:優先使用 Package 任務,而非 Root 任務

相較於 Root 任務,請優先使用 Package 任務。

建立任務/指令稿 (scripts)/管線時,你必須預設使用 Package 任務:

  1. 將指令稿加入至各相關套件的 package.json
  2. 在根目錄的 turbo.json 中註冊該任務
  3. 根目錄的 package.json 僅透過 turbo run <task> 進行委派

當任務邏輯可以放在個別套件時,切勿將其放在根目錄的 package.json 中。這會破壞 Turborepo 的平行處理能力。

// 正確做法:在各個套件中定義指令稿
// 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" } }
// turbo.json - 註冊任務
{
  "tasks": {
    "build": { "dependsOn": ["^build"], "outputs": ["dist/**"] },
    "lint": {},
    "test": { "dependsOn": ["build"] }
  }
}
// 根目錄 package.json - 僅進行委派,不包含任務邏輯
{
  "scripts": {
    "build": "turbo run build",
    "lint": "turbo run lint",
    "test": "turbo run test"
  }
}
// 錯誤做法 - 會破壞平行處理能力
// 根目錄 package.json
{
  "scripts": {
    "build": "cd apps/web && next build && cd ../api && tsc",
    "lint": "eslint apps/ packages/",
    "test": "vitest"
  }
}

Root 任務 (//#taskname) 僅適用於確實無法存在於個別套件中的任務,例如 Vitest Projects 的 //#test、全專案層級的發布指令稿 (release scripts),或是本身不呼叫 turbo 的工具鏈。

次要規則:turbo runturbo 的使用時機

當指令被寫入程式碼或設定檔中時,請一律使用 turbo run

// package.json - 一律使用 "turbo run"
{
  "scripts": {
    "build": "turbo run build"
  }
}
# CI 工作流程 - 一律使用 "turbo run"
- run: turbo run build --affected

簡寫形式 turbo <tasks> 僅適用於由人工或 Agent 在終端機直接輸入的單次命令。切勿將 turbo build 寫入 package.json、CI 設定或指令稿中。

快速決策樹

「我需要設定一個任務」

設定任務?
├─ 定義任務相依性 → references/configuration/tasks.md
├─ Lint / 型別檢查 (平行處理 + 快取) → 使用中轉節點模式 (Transit Nodes,見下文)
├─ 指定建置輸出產物 → references/configuration/tasks.md#outputs
├─ 處理環境變數 → references/environment/RULE.md
├─ 設定開發/監聽 (dev/watch) 任務 → references/configuration/tasks.md#persistent
├─ 特定套件設定 → references/configuration/RULE.md#package-configurations
└─ 全域設定 (cacheDir, daemon) → references/configuration/global-options.md

「我的快取沒有生效」

快取問題?
├─ 任務已執行但未還原輸出產物 → 缺少 `outputs` 鍵值
├─ 快取意外未命中 (Cache miss) → references/caching/gotchas.md
├─ 需要偵錯 Hash 輸入值 → 使用 --summarize 或 --dry
├─ 完全跳過快取 → 使用 --force 或 cache: false
├─ 遠端快取無法運作 → references/caching/remote-cache.md
└─ 環境變數導致快取未命中 → references/environment/gotchas.md

「我想僅執行變更過的套件」

僅執行變更部分?
├─ 變更的套件 + 其受影響者 (推薦) → turbo run build --affected
├─ 自訂基準分支 (Base branch) → --affected --affected-base=origin/develop
├─ 手動 git 比對 → --filter=...[origin/main]
└─ 檢視所有篩選選項 → references/filtering/RULE.md

--affected 是僅執行變更套件的主要方式。 它會自動與預設分支進行比對,並包含所有相依於該套件的受影響套件。

「我想篩選指定套件」

篩選套件?
├─ 僅變更過的套件 → --affected(見上文)
├─ 依套件名稱 → --filter=web
├─ 依目錄路徑 → --filter=./apps/*
├─ 套件 + 其前置相依套件 → --filter=web...
├─ 套件 + 其後續受影響套件 → --filter=...web
└─ 複雜組合條件 → references/filtering/patterns.md

「環境變數沒有生效」

環境變數問題?
├─ 變數在執行期 (Runtime) 無法存取 → 嚴格模式篩選 (預設值)
├─ 帶有錯誤環境變數卻快取命中 → 變數未列在 `env` 鍵值中
├─ 修改 .env 未觸發重新建置 → .env 未列在 `inputs` 中
├─ CI 環境變數遺失 → references/environment/gotchas.md
└─ 框架環境變數 (NEXT_PUBLIC_*) → 透過推論自動包含

「我需要設定 CI」

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

「我想在開發時監聽檔案變更」

監聽模式 (Watch mode)?
├─ 檔案變更時重新執行任務 → turbo watch (references/watch/RULE.md)
├─ 帶有相依性的開發伺服器 → 使用 `with` 鍵值 (references/configuration/tasks.md#with)
├─ 相依套件變更時重啟開發伺服器 → 使用 `interruptible: true`
└─ 持續執行的開發任務 → 使用 `persistent: true`

「我需要建立或規劃套件結構」

建立/規劃套件結構?
├─ 建立內部套件 → references/best-practices/packages.md
├─ 儲存庫結構 → references/best-practices/structure.md
├─ 相依性管理 → references/best-practices/dependencies.md
├─ 最佳做法總覽 → references/best-practices/RULE.md
├─ 即時編譯 (JIT) vs 事先編譯 (Compiled) 套件 → references/best-practices/packages.md#compilation-strategies
└─ 在應用程式之間共用程式碼 → references/best-practices/RULE.md#package-types

「我該如何規劃 Monorepo 的架構?」

Monorepo 架構?
├─ 標準配置 (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

「我想強制執行架構邊界約束」

強制執行邊界?
├─ 檢查違規項目 → turbo boundaries
├─ 為套件加上標籤 (Tag) → references/boundaries/RULE.md#tags
├─ 限制套件之間的匯入關係 → references/boundaries/RULE.md#rule-types
└─ 防止跨套件直接檔案匯入 → references/boundaries/RULE.md

關鍵反模式 (Anti-Patterns)

在程式碼中使用 turbo 簡寫形式

建議在 package.json 指令稿與 CI 管線中統一使用 turbo run 簡寫形式 turbo <task> 僅專為終端機互動式操作而設計。

// 錯誤 - 在 package.json 中使用簡寫形式
{
  "scripts": {
    "build": "turbo build",
    "dev": "turbo dev"
  }
}

// 正確
{
  "scripts": {
    "build": "turbo run build",
    "dev": "turbo run dev"
  }
}
# 錯誤 - 在 CI 中使用簡寫形式
- run: turbo build --affected

# 正確
- run: turbo run build --affected

根目錄指令稿繞過 Turbo

根目錄 package.json 中的指令稿必須委派給 turbo run,而不是直接執行任務。

// 錯誤 - 完全繞過 turbo
{
  "scripts": {
    "build": "bun build",
    "dev": "bun dev"
  }
}

// 正確 - 委派給 turbo
{
  "scripts": {
    "build": "turbo run build",
    "dev": "turbo run dev"
  }
}

使用 && 串接 Turbo 任務

請勿使用 && 串接 turbo 任務。交由 Turbo 來進行工作協同編排 (orchestrate)。

// 錯誤 - turbo 任務未使用 turbo run
{
  "scripts": {
    "changeset:publish": "bun build && changeset publish"
  }
}

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

手動建置相依套件的 prebuild 指令稿

prebuild 這樣手動建置其他套件的指令稿,會繞過 Turborepo 的相依性圖表。

// 錯誤 - 手動建置相依套件
{
  "scripts": {
    "prebuild": "cd ../../packages/types && bun run build && cd ../utils && bun run build",
    "build": "next build"
  }
}

不過,修復方式取決於是否已宣告工作區相依性 (workspace dependencies):

  1. 若已宣告相依性(例如 package.json 中寫有 "@repo/types": "workspace:*"),請直接移除 prebuild 指令稿。Turbo 的 dependsOn: ["^build"] 會自動處理建置順序。

  2. 若未宣告相依性,則 prebuild 是因為缺乏相依關係而無法觸發 ^build 才產生的折衷做法。修復步驟為:

    • 將相依套件加入 package.json:"@repo/types": "workspace:*"
    • 接著移除 prebuild 指令稿
// 正確 - 宣告相依性,交由 turbo 處理建置順序
// package.json
{
  "dependencies": {
    "@repo/types": "workspace:*",
    "@repo/utils": "workspace:*"
  },
  "scripts": {
    "build": "next build"
  }
}

// turbo.json
{
  "tasks": {
    "build": {
      "dependsOn": ["^build"]
    }
  }
}

關鍵觀念: ^build 只會執行已列為相依套件的建置任務。未宣告相依性 = 無法自動進行建置排序。

過於寬鬆的 globalDependencies

globalDependencies 會透過全域 Hash (global hash) 影響所有套件中的「所有」任務——即使在 inputs 中使用否定匹配 (negation globs),任務也無法選擇排除特定檔案。請務必指定具體的檔案範圍。

// 錯誤 - 範圍過大,影響所有 hash 計算
{
  "globalDependencies": ["**/.env.*local"]
}

// 較佳 - 移至任務層級的 inputs
{
  "globalDependencies": [".env"],
  "tasks": {
    "build": {
      "inputs": ["$TURBO_DEFAULT$", ".env*"],
      "outputs": ["dist/**"]
    }
  }
}

開啟 futureFlags.globalConfiguration 後,此問題可獲得緩解,因為 global.inputs 的檔案會納入各任務自身的 inputs 中(而非全域 hash)。如此一來,個別任務即可排除特定檔案:

// 最佳 - 使用 global.inputs 並在個別任務中排除檔案
{
  "futureFlags": { "globalConfiguration": true },
  "global": {
    "inputs": [".env"]
  },
  "tasks": {
    "build": { "outputs": ["dist/**"] },
    "lint": {
      "inputs": ["$TURBO_DEFAULT$", "!$TURBO_ROOT$/.env"]
    }
  }
}

重覆的任務設定

請檢查跨任務之間是否有重複的設定可予以整合。Turborepo 支援共用設定模式。

// 錯誤 - 跨任務重複設定 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
    }
  }
}

何時使用全域 (Global) vs 任務層級 (Task-level):

  • globalEnv / globalDependencies - 影響所有任務,僅適用於真正跨全域共用的設定
  • 任務層級的 env / inputs - 僅在特定任務需要時使用

非反模式:龐大的 env 陣列

龐大的 env 陣列(即便超過 50 個變數)並非問題。這通常代表使用者非常完整地宣告了建置過程所需的環境變數相依性。請勿將此標記為問題。