turborepo
Turborepoモノレポビルドシステムに関するガイダンスを提供します。turbo.json、タスクパイプライン、dependsOn、キャッシング、リモートキャッシュ、「turbo」CLI、--filter、--affected、CI最適化、環境変数、内部パッケージ、モノレポ構造およびベストプラクティス、そして境界設定に関するご質問に対応します。 ユーザーがタスク/ワークフロー/パイプラインを設定する場合、パッケージを作成する場合、モノレポをセットアップする場合、アプリ間でコードを共有する場合、変更/影響を受けたパッケージを実行する場合、キャッシュをデバッグする場合、またはapps/packagesディレクトリを使用している場合にご利用ください。
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.
SKILL.md 本文
Turborepo スキル
JavaScript/TypeScript モノレポ向けのビルドシステム。Turborepo はタスク出力をキャッシュし、依存関係グラフに基づいてタスクを並列実行します。
重要: ルートタスクではなくパッケージタスクを作成する
ルートタスクを作成しないでください。常にパッケージタスクを作成してください。
タスク/スクリプト/パイプラインを作成する際は、以下の手順に従う必要があります:
- 各関連パッケージの
package.jsonにスクリプトを追加する - ルートの
turbo.jsonにタスクを登録する - ルートの
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"
}
}
ルートタスク (//#taskname) は、パッケージに本当に存在できないタスク (稀) のみで使用してください。
二次ルール: turbo run vs turbo
コマンドをコードに書き込む場合は常に turbo run を使用してください:
// package.json - 常に "turbo run"
{
"scripts": {
"build": "turbo run build"
}
}
# CI ワークフロー - 常に "turbo run"
- run: turbo run build --affected
短縮形の turbo <tasks> は、人やエージェントが直接入力する一度きりのターミナルコマンド向けのみです。 package.json、CI、またはスクリプトに turbo build を書き込まないでください。
クイック判定ツリー
「タスクを設定する必要があります」
タスクを設定しますか?
├─ タスク依存関係を定義 → 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` キーが不足している
├─ キャッシュミスが予期せず発生 → references/caching/gotchas.md
├─ ハッシュ入力をデバッグする必要がある → --summarize または --dry を使用
├─ キャッシュを完全にスキップしたい → --force または cache: false を使用
├─ リモートキャッシュが機能していない → references/caching/remote-cache.md
└─ 環境によるミス → references/environment/gotchas.md
「変更されたパッケージのみを実行したいです」
変更されたものだけを実行しますか?
├─ 変更されたパッケージ + 依存するパッケージ (推奨) → turbo run build --affected
├─ カスタムベースブランチ → --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
「環境変数が機能していません」
環境の問題?
├─ 実行時に変数が利用できない → Strict モードフィルタリング (デフォルト)
├─ 間違った環境でキャッシュヒット → 変数が `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
「開発中に変更を監視したいです」
ウォッチモード?
├─ 変更時にタスクを再実行 → turbo watch (references/watch/RULE.md)
├─ 依存関係のある dev サーバー → `with` キーを使用 (references/configuration/tasks.md#with)
├─ 依存関係の変更時に dev サーバーを再起動 → `interruptible: true` を使用
└─ 永続的な dev タスク → `persistent: true` を使用
「パッケージを作成/構造化する必要があります」
パッケージ作成/構造化?
├─ 内部パッケージを作成 → references/best-practices/packages.md
├─ リポジトリ構造 → references/best-practices/structure.md
├─ 依存関係管理 → references/best-practices/dependencies.md
├─ ベストプラクティス概要 → references/best-practices/RULE.md
├─ JIT vs コンパイル済みパッケージ → references/best-practices/packages.md#compilation-strategies
└─ アプリ間でのコード共有 → references/best-practices/RULE.md#package-types
「モノレポをどのように構造化すべきですか?」
モノレポ構造?
├─ 標準レイアウト (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
├─ パッケージにタグを付ける → references/boundaries/RULE.md#tags
├─ どのパッケージが他をインポートできるかを制限 → references/boundaries/RULE.md#rule-types
└─ クロスパッケージ ファイルインポートを防止 → references/boundaries/RULE.md
重大なアンチパターン
コードで turbo 短縮形を使用する
turbo run は package.json スクリプトと CI パイプラインで推奨されます。 短縮形の 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 に調整させてください。
// 間違い - turbo run を使用していない turbo タスク
{
"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"
}
}
ただし、修正はワークスペース依存関係が宣言されているかどうかによって異なります:
-
依存関係が宣言されている場合 (例:
"@repo/types": "workspace:*"in package.json)、prebuildスクリプトを削除してください。Turborepo のdependsOn: ["^build"]がこれを自動的に処理します。 -
依存関係が宣言されていない場合、
prebuildが存在するのは^buildが依存関係がないとトリガーされないためです。修正は以下の通りです:- package.json に依存関係を追加:
"@repo/types": "workspace:*" - その後
prebuildスクリプトを削除
- package.json に依存関係を追加:
// 正解 - 依存関係を宣言し、turbo にビルド順序を処理させる
// package.json
{
"dependencies": {
"@repo/types": "workspace:*",
"@repo/utils": "workspace:*"
},
"scripts": {
"build": "next build"
}
}
// turbo.json
{
"tasks": {
"build": {
"dependsOn": ["^build"]
}
}
}
重要な洞察: ^build は依存関係としてリストされているパッケージ内の build のみを実行します。依存関係宣言なし = 自動ビルド順序なし。
過度に広い globalDependencies
globalDependencies はすべてのパッケージのすべてのタスクに影響します。具体的にしてください。
// 間違い - すべてのハッシュに影響する重いハンマー
{
"globalDependencies": ["**/.env.*local"]
}
// より良い - タスクレベルの inputs に移動
{
"globalDependencies": [".env"],
"tasks": {
"build": {
"inputs": ["$TURBO_DEFAULT$", ".env*"],
"outputs": ["dist/**"]
}
}
}
繰り返されるタスク設定
タスク全体で繰り返される設定を探し、それを折りたたむことができるかを確認してください。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
}
}
}
グローバルとタスクレベルのいつ:
globalEnv/globalDependencies- すべてのタスクに影響、真に共有された設定に使用- タスクレベルの
env/inputs- 特定のタスクのみが必要な場合に使用
アンチパターンではない: 大きな env 配列
大きな env 配列 (50 以上の変数でも) は問題 ではありません。 通常は、ユーザーが自分たちのビルドの環境依存関係について十分に宣言していることを意味します。これを問題としてフラグを立てないでください。
--parallel フラグを使用する
--parallel フラグは Turborepo の依存関係グラフをバイパスします。タスクが並列実行が必要な場合は、代わりに dependsOn を正しく設定してください。
# 間違い - 依存関係グラフをバイパス
turbo run lint --parallel
# 正解 - dependsOn を適切に設定してタスクが並列実行を許可
# turbo.json で、dependsOn を適切に設定 (または transit nodes を使用)
turbo run lint
ルート turbo.json でのパッケージ固有のタスクオーバーライド
複数のパッケージが異なるタスク設定が必要な場合、ルート turbo.json を package#task オーバーライドで埋めるのではなく、パッケージ設定 (各パッケージの turbo.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 を参照してください。
inputs でパッケージ外を走査するために ../ を使用する
../ のような相対パスを使用してパッケージ外のファイルを参照しないでください。代わりに $TURBO_ROOT$ を使用してください。
// 間違い - パッケージ外を走査
{
"tasks": {
"build": {
"inputs": ["$TURBO_DEFAULT$", "../shared-config.json"]
}
}
}
// 正解 - リポジトリルートに $TURBO_ROOT$ を使用
{
"tasks": {
"build": {
"inputs": ["$TURBO_DEFAULT$", "$TURBO_ROOT$/shared-config.json"]
}
}
}
ファイル生成タスクの欠落した outputs
outputs が欠落しているとフラグを立てる前に、タスクが実際に何を生成しているかを確認してください:
- パッケージのスクリプトを読む (例:
"build": "tsc","test": "vitest") - ディスクにファイルを書き込むか、stdout のみに出力するかを判断
- キャッシュされるべきファイルを生成する場合のみフラグを立てる
// 間違い: build はファイルを生成するがキャッシュされない
{
"tasks": {
"build": {
"dependsOn": ["^build"]
}
}
}
// 正解: build の出力がキャッシュされる
{
"tasks": {
"build": {
"dependsOn": ["^build"],
"outputs": ["dist/**"]
}
}
}
フレームワーク別の一般的な outputs:
- Next.js:
[".next/**", "!.next/cache/**"] - Vite/Rollup:
["dist/**"] - tsc:
["dist/**"]またはカスタムoutDir
TypeScript --noEmit でもキャッシュファイルを生成できます:
tsconfig.json で incremental: true の場合、tsc --noEmit は JS を出力しなくても .tsbuildinfo ファイルを書き込みます。出力がないと仮定する前に tsconfig を確認してください:
// tsconfig に incremental: true がある場合、tsc --noEmit はキャッシュファイルを生成
{
"tasks": {
"typecheck": {
"outputs": ["node_modules/.cache/tsbuildinfo.json"] // または tsBuildInfoFile が指す場所
}
}
}
TypeScript タスクの正しい outputs を決定するには:
- tsconfig で
incrementalまたはcompositeが有効になっているかをチェック tsBuildInfoFileをカスタムキャッシュ場所でチェック (デフォルト:outDirの横またはプロジェクトルート)- インクリメンタルモードがない場合、
tsc --noEmitはファイルを生成しない
^build vs build の混同
{
"tasks": {
// ^build = 最初に依存関係で build を実行 (このパッケージがインポートする他のパッケージ)
"build": {
"dependsOn": ["^build"]
},
// build (^ なし) = 最初に同じパッケージで build を実行
"test": {
"dependsOn": ["build"]
},
// pkg#task = 特定のパッケージのタスク
"deploy": {
"dependsOn": ["web#build"]
}
}
}
ハッシュされていない環境変数
// 間違い: API_URL の変更はリビルドを引き起こさない
{
"tasks": {
"build": {
"outputs": ["dist/**"]
}
}
}
// 正解: API_URL の変更はキャッシュを無効化
{
"tasks": {
"build": {
"outputs": ["dist/**"],
"env": ["API_URL", "API_KEY"]
}
}
}
Inputs に .env ファイルがない
Turborepo は .env ファイルをロードしません - あなたのフレームワークがそれを行います。しかし Turborepo は変更について知る必要があります:
// 間違い: .env の変更はキャッシュを無効化しない
{
"tasks": {
"build": {
"env": ["API_URL"]
}
}
}
// 正解: .env ファイルの変更はキャッシュを無効化
{
"tasks": {
"build": {
"env": ["API_URL"],
"inputs": ["$TURBO_DEFAULT$", ".env", ".env.*"]
}
}
}
モノレポのルート .env ファイル
リポジトリルートの .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 を使用して、何が共有されているかを明確にし、なぜかを説明してください。
Strict モードフィルタリング CI 変数
デフォルトでは、Turborepo は環境変数を env/globalEnv のものだけにフィルターします。CI 変数がない可能性があります:
// CI スクリプトが GITHUB_TOKEN を必要としても env にない場合:
{
"globalPassThroughEnv": ["GITHUB_TOKEN", "CI"],
"tasks": { ... }
}
または --env-mode=loose を使用 (本番環境には推奨されません)。
アプリ内の共有コード (パッケージであるべき)
// 間違い: アプリ内の共有コード
apps/
web/
shared/ # これはモノレポの原則を壊します!
utils.ts
// 正解: パッケージに抽出
packages/
utils/
src/utils.ts
パッケージ境界を越えてファイルにアクセスする
// 間違い: 別のパッケージの内部に到達する
import { Button } from "../../packages/ui/src/button";
// 正解: インストールして適切にインポート
import { Button } from "@repo/ui/button";
ルートの依存関係が多すぎる
// 間違い: アプリの依存関係がルートに
{
"dependencies": {
"react": "^18",
"next": "^14"
}
}
// 正解: リポジトリツールのみがルートに
{
"devDependencies": {
"turbo": "latest"
}
}
一般的なタスク設定
標準ビルドパイプライン
{
"$schema": "https://v2-8-18-canary-7.turborepo.dev/schema.json",
"tasks": {
"build": {
"dependsOn": ["^build"],
"outputs": ["dist/**", ".next/**", "!.next/cache/**"]
},
"dev": {
"cache": false,
"persistent": true
}
}
}
並列実行が必要でキャッシュ無効化が必要なタスクがある場合は、transit タスクを追加してください (下記参照)。
`
ライセンス: MIT(寛容ライセンスのため全文を引用しています) · 原本リポジトリ
詳細情報
- 作者
- ComeOnOliver
- ライセンス
- MIT
- 最終更新
- 2026/5/11
Source: https://github.com/ComeOnOliver/skillshub / ライセンス: MIT