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)は、Vitest Projects の //#test、リポジトリ全体のリリーススクリプト、または turbo 自体を呼び出さないツーリングなど、パッケージに真に存在できないタスクのみを対象とします。
副次ルール: 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> はワンオフのターミナルコマンドのみで、人またはエージェントが直接入力します。turbo build を package.json、CI、またはスクリプトに書き込まないでください。
クイック判断ツリー
「タスクを設定する必要があります」
タスクを設定しますか?
├─ タスク依存関係を定義 → references/configuration/tasks.md
├─ リント/型チェック (並列 + キャッシング) → トランジットノードパターンを使用 (下記参照)
├─ ビルド出力を指定 → 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)
├─ 依存関係を持つ開発サーバー → `with` キーを使用 (references/configuration/tasks.md#with)
├─ 依存関係の変更時に開発サーバーを再起動 → `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
├─ パッケージタイプ (apps 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"
}
}
ただし、修正はワークスペース依存関係が宣言されているかどうかに依存します:
-
依存関係が宣言されている場合 (例: package.json 内の
"@repo/types": "workspace:*")、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 は依存関係として列挙されているパッケージのビルドのみを実行します。依存関係宣言がない = 自動的なビルド順序がない。
過度に広い globalDependencies
globalDependencies はグローバルハッシュを通じてすべてのパッケージのすべてのタスクに影響します — タスクは inputs の否定グロブでも特定ファイルをオプトアウトできません。具体的にしてください。
// 誤り - 大きなハンマー、すべてのハッシュに影響
{
"globalDependencies": ["**/.env.*local"]
}
// より良い - タスクレベルの入力に移動
{
"globalDependencies": [".env"],
"tasks": {
"build": {
"inputs": ["$TURBO_DEFAULT$", ".env*"],
"outputs": ["dist/**"]
}
}
}
futureFlags.globalConfiguration を使用すると、global.inputs ファイルが各タスクの入力にフォールドされるため (グローバルハッシュではなく)、この問題は軽減されます。タスクは特定のファイルを除外できます:
// 最良 - 否定グロブを使用した 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
}
}
}
グローバル vs タスクレベルを使用する時機:
globalEnv/globalDependencies- すべてのタスクに影響、真に共有された設定に使用- タスクレベルの
env/inputs- 特定のタスクのみが必要な場合に使用
アンチパターンではありません: 大きな env 配列
大きな env 配列 (50 以上の変数でも) は問題ではありません。 これは通常、ユーザーがビルドの環境依存関係を詳細に宣言したことを意味します。これを問題として指摘しないでください。
--parallel フラグを使用する
--parallel フラグは Turborepo の依存関係グラフをバイパスします。タスクが並列実行する必要がある場合は、代わりに dependsOn を正しく設定してください。
# 誤り - 依存関係グラフをバイパス
turbo run lint --parallel
# 正しい - dependsOn を適切に設定してタスクを並列実行できるようにする
# turbo.json で、dependsOn を適切に設定 (またはトランジットノードを使用)
turbo run lint
ルート turbo.json 内のパッケージ固有のタスクオーバーライド
複数のパッケージが異なるタスク設定を必要とする場合、ルート turbo.json を package#task オーバーライドで散らかすのではなく、パッケージ設定 (各パッケージの turbo.json) を使用してください。
// 誤り - 多くのパッケージ固有のオーバーライドを持つ root 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 にのみ出力するかを判断する
- タスクがキャッシュされるべきファイルを生成する場合にのみフラグを立てる
// 誤り: ビルドがファイルを生成しますが、キャッシュされていない
{
"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 を確認してください:
// tsconfig で incremental: true の場合、tsc --noEmit はキャッシュファイルを生成
{
"tasks": {
"typecheck": {
"outputs": ["node_modules/.cache/tsbuildinfo.json"] // または tsBuildInfoFile が指すところ
}
}
}
TypeScript タスクの正しい出力を判断するには:
- 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 ファイルはアンチパターンです — 小規模なモノレポやスターターテンプレートであっても。これはパッケージ間の暗黙的なカップリングを作成し、どのパッケージがどの変数に依存しているかが不明確になります。
// 誤り - root .env がすべてのパッケージに暗黙的に影響
my-monorepo/
├── .env # どのパッケージがこれを使用しますか?
├── apps/
│ ├── web/
│ └── api/
└── packages/
// 正しい - それを必要とするパッケージ内の .env ファイル
my-monorepo/
├── apps/
│ ├── web/
│ │ └── .env # 明確: web は DATABASE_URL を必要
│ └── api/
│ └── .env # 明確: api は API_KEY を必要
└── packages/
root .env の問題:
- どのパッケージがどの変数を消費するかが不明確
- すべてのパッケージがすべての変数を取得 (必要ないものも)
- キャッシュ無効化が粗粒度 (root .env の変更がすべてを無効化)
- セキュリティリスク: パッケージが他のパッケージ向けのセンシティブな変数に誤ってアクセスする可能性
- 悪い習慣は小さく始まる — スターターテンプレートは正しいパターンをモデル化すべき
変数を共有する必要がある場合、globalEnv を使用して明示的にし、理由を文書化してください。
Strict モードフィルタリング CI 変数
デフォルトでは、Turborepo は環境変数を env/globalEnv 内のもののみにフィルタリングします。CI 変数が不足している可能性があります:
// CI スクリプトが GITHUB_TOKEN を必要としますが env
ライセンス: MIT(寛容ライセンスのため全文を引用しています) · 原本リポジトリ
詳細情報
- 作者
- ibousfiha
- ライセンス
- MIT
- 最終更新
- 2026/5/2
Source: https://github.com/ibousfiha/better-t-nest-template / ライセンス: MIT