turborepo-caching について
Turborepoのビルドキャッシュ最適化ガイドです。ビルドパイプライン、リモートキャッシュ、CIを設定する開発者向けに、設定テンプレートや対象の絞り込み、キャッシュの調査方法を紹介します。
主な機能
- 01ビルドパイプライン設定の指針
- 02ローカルとリモートのキャッシュ設定
- 03タスクのフィルタリングと範囲指定
- 04キャッシュミスの調査
- 05CI設定テンプレート
活用シーン
- 01新しいTurborepoプロジェクトのキャッシュ設定
- 02CIでのビルド最適化
- 03リモートキャッシュの構築
- 04キャッシュミスの調査
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ wshobson/ agents --skill turborepo-cachingインストール後、Claude Code で/turborepo-cachingを入力して読み込まれたか確認します。
詳細
Turborepo のキャッシュ
Turborepo によるビルド最適化の本番運用パターン。
このスキルを使う場面
- 新しい Turborepo プロジェクトをセットアップするとき
- ビルドパイプラインを構成するとき
- リモートキャッシュを実装するとき
- CI/CD のパフォーマンスを最適化するとき
- 他のモノレポツールから移行するとき
- キャッシュミスをデバッグするとき
中核となる概念
1. Turborepo のアーキテクチャ
Workspace Root/
├── apps/
│ ├── web/
│ │ └── package.json
│ └── docs/
│ └── package.json
├── packages/
│ ├── ui/
│ │ └── package.json
│ └── config/
│ └── package.json
├── turbo.json
└── package.json
2. パイプラインの概念
| 概念 | 説明 |
|---|---|
| dependsOn | 先に完了する必要があるタスク |
| cache | 出力をキャッシュするかどうか |
| outputs | キャッシュするファイル |
| inputs | キャッシュキーに影響するファイル |
| persistent | 長時間実行されるタスク (開発サーバー) |
テンプレート
テンプレート 1: turbo.json の構成
{
"$schema": "https://turbo.build/schema.json",
"globalDependencies": [".env", ".env.local"],
"globalEnv": ["NODE_ENV", "VERCEL_URL"],
"pipeline": {
"build": {
"dependsOn": ["^build"],
"outputs": ["dist/**", ".next/**", "!.next/cache/**"],
"env": ["API_URL", "NEXT_PUBLIC_*"]
},
"test": {
"dependsOn": ["build"],
"outputs": ["coverage/**"],
"inputs": ["src/**/*.tsx", "src/**/*.ts", "test/**/*.ts"]
},
"lint": {
"outputs": [],
"cache": true
},
"typecheck": {
"dependsOn": ["^build"],
"outputs": []
},
"dev": {
"cache": false,
"persistent": true
},
"clean": {
"cache": false
}
}
}
テンプレート 2: パッケージ固有のパイプライン
// apps/web/turbo.json
{
"$schema": "https://turbo.build/schema.json",
"extends": ["//"],
"pipeline": {
"build": {
"outputs": [".next/**", "!.next/cache/**"],
"env": ["NEXT_PUBLIC_API_URL", "NEXT_PUBLIC_ANALYTICS_ID"]
},
"test": {
"outputs": ["coverage/**"],
"inputs": ["src/**", "tests/**", "jest.config.js"]
}
}
}
テンプレート 3: Vercel によるリモートキャッシュ
# Login to Vercel
npx turbo login
# Link to Vercel project
npx turbo link
# Run with remote cache
turbo build --remote-only
# CI environment variables
TURBO_TOKEN=your-token
TURBO_TEAM=your-team
# .github/workflows/ci.yml
name: CI
on:
push:
branches: [main]
pull_request:
env:
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
TURBO_TEAM: ${{ vars.TURBO_TEAM }}
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: "npm"
- name: Install dependencies
run: npm ci
- name: Build
run: npx turbo build --filter='...[origin/main]'
- name: Test
run: npx turbo test --filter='...[origin/main]'
テンプレート 4: セルフホストのリモートキャッシュ
// Custom remote cache server (Express)
import express from "express";
import { createReadStream, createWriteStream } from "fs";
import { mkdir } from "fs/promises";
import { join } from "path";
const app = express();
const CACHE_DIR = "./cache";
// Get artifact
app.get("/v8/artifacts/:hash", async (req, res) => {
const { hash } = req.params;
const team = req.query.teamId || "default";
const filePath = join(CACHE_DIR, team, hash);
try {
const stream = createReadStream(filePath);
stream.pipe(res);
} catch {
res.status(404).send("Not found");
}
});
// Put artifact
app.put("/v8/artifacts/:hash", async (req, res) => {
const { hash } = req.params;
const team = req.query.teamId || "default";
const dir = join(CACHE_DIR, team);
const filePath = join(dir, hash);
await mkdir(dir, { recursive: true });
const stream = createWriteStream(filePath);
req.pipe(stream);
stream.on("finish", () => {
res.json({
urls: [`${req.protocol}://${req.get("host")}/v8/artifacts/${hash}`],
});
});
});
// Check artifact exists
app.head("/v8/artifacts/:hash", async (req, res) => {
const { hash } = req.params;
const team = req.query.teamId || "default";
const filePath = join(CACHE_DIR, team, hash);
try {
await fs.access(filePath);
res.status(200).end();
} catch {
res.status(404).end();
}
});
app.listen(3000, "127.0.0.1");
// turbo.json for the local cache demo
{
"remoteCache": {
"signature": false
}
}
# This local demo does not authenticate the dummy token.
# Use only disposable artifacts on a trusted machine; do not expose the server.
turbo build --api="http://127.0.0.1:3000" --token="my-token" --team="my-team"
テンプレート 5: フィルタリングとスコープ設定
# Build specific package
turbo build --filter=@myorg/web
# Build package and its dependencies
turbo build --filter=@myorg/web...
# Build package and its dependents
turbo build --filter=...@myorg/ui
# Build changed packages since main
turbo build --filter='...[origin/main]'
# Build packages in directory
turbo build --filter='./apps/*'
# Combine filters
turbo build --filter=@myorg/web --filter=@myorg/docs
# Exclude package
turbo build --filter='!@myorg/docs'
# Include dependencies of changed
turbo build --filter='...[HEAD^1]...'
テンプレート 6: 高度なパイプライン構成
{
"$schema": "https://turbo.build/schema.json",
"pipeline": {
"build": {
"dependsOn": ["^build"],
"outputs": ["dist/**"],
"inputs": ["$TURBO_DEFAULT$", "!**/*.md", "!**/*.test.*"]
},
"test": {
"dependsOn": ["^build"],
"outputs": ["coverage/**"],
"inputs": ["src/**", "tests/**", "*.config.*"],
"env": ["CI", "NODE_ENV"]
},
"test:e2e": {
"dependsOn": ["build"],
"outputs": [],
"cache": false
},
"deploy": {
"dependsOn": ["build", "test", "lint"],
"outputs": [],
"cache": false
},
"db:generate": {
"cache": false
},
"db:push": {
"cache": false,
"dependsOn": ["db:generate"]
},
"@myorg/web#build": {
"dependsOn": ["^build", "@myorg/db#db:generate"],
"outputs": [".next/**"],
"env": ["NEXT_PUBLIC_*"]
}
}
}
テンプレート 7: ルートの package.json のセットアップ
{
"name": "my-turborepo",
"private": true,
"workspaces": ["apps/*", "packages/*"],
"scripts": {
"build": "turbo build",
"dev": "turbo dev",
"lint": "turbo lint",
"test": "turbo test",
"clean": "turbo clean && rm -rf node_modules",
"format": "prettier --write \"**/*.{ts,tsx,md}\"",
"changeset": "changeset",
"version-packages": "changeset version",
"release": "turbo build --filter=./packages/* && changeset publish"
},
"devDependencies": {
"turbo": "^1.10.0",
"prettier": "^3.0.0",
"@changesets/cli": "^2.26.0"
},
"packageManager": "[email protected]"
}
キャッシュのデバッグ
# Dry run to see what would run
turbo build --dry-run
# Verbose output with hashes
turbo build --verbosity=2
# Show task graph
turbo build --graph
# Force no cache
turbo build --force
# Show cache status
turbo build --summarize
# Debug specific task
TURBO_LOG_VERBOSITY=debug turbo build --filter=@myorg/web
ベストプラクティス
やるべきこと
- 入力 (inputs) を明示的に定義する - キャッシュの無効化を避ける
- ワークスペースプロトコルを使う -
"@myorg/ui": "workspace:*" - リモートキャッシュを有効にする - CI とローカルで共有する
- CI でフィルタリングする - 影響を受けたパッケージだけをビルドする
- ビルド出力をキャッシュする - ソースファイルではなく
やってはいけないこと
- 開発サーバーをキャッシュしない -
persistent: trueを使う - env にシークレットを含めない - 実行時の環境変数を使う
- dependsOn を無視しない - 競合状態を引き起こす
- 過度にフィルタリングしない - 依存関係を見落とす可能性がある
コメント
Markdown 対応