turborepo について
JavaScript と TypeScript のモノレポで Turborepo を使う方法をまとめたスキルです。タスクの依存関係、キャッシュ、ワークスペース設定、CI の運用を扱い、複数パッケージを管理する開発者向けです。
主な機能
- 01依存関係に基づくタスクパイプライン設定
- 02ローカル・リモートキャッシュの利用
- 03パッケージや変更によるタスク選択
- 04デプロイ用ワークスペースの絞り込み
- 05ワークスペースパッケージの設定
活用シーン
- 01モノレポの反復ビルドの高速化
- 02変更されたパッケージだけでの CI 実行
- 03アプリ別 Docker ビルド入力の準備
- 04ビルド・テスト・lint タスクの調整
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ timelessco/ recollect --skill turborepoインストール後、Claude Code で/turborepoを入力して読み込まれたか確認します。
詳細
Turborepo スキル
Turborepo は、Rust で記述された、JavaScript および TypeScript のモノレポ向けに最適化された高性能ビルドシステムです。インテリジェントなキャッシュ、タスクのオーケストレーション、リモート実行機能を備え、開発ワークフローを大幅に高速化します。
リファレンス
https://turborepo.com/llms.txt
このスキルを使用するタイミング
次のような場合にこのスキルを使用します。
- 複数のパッケージを含む新しいモノレポをセットアップする
- 既存のモノレポのビルドパフォーマンスを最適化する
- パッケージ間のタスクパイプラインを実装する
- インテリジェントなキャッシュ戦略を設定する
- チーム向けにリモートキャッシュをセットアップする
- 依存関係を考慮してタスクをオーケストレーションする
- モノレポを CI/CD パイプラインに統合する
- Lerna、Nx、その他のモノレポツールから移行する
- マイクロフロントエンドや共有ライブラリを構築する
- ワークスペースの依存関係を管理する
主な概念
1. モノレポアーキテクチャ
Turborepo は、単一のリポジトリ内のパッケージにコードを整理します。
- ルートパッケージ:ワークスペース設定を含みます
- 内部パッケージ:共有ライブラリ、ユーティリティ、設定
- アプリケーション:フロントエンドアプリ、バックエンドサービスなど
- ワークスペース:npm/yarn/pnpm のワークスペース設定
2. タスクパイプライン
タスクは依存関係グラフに沿って整理されます。
- タスクの依存関係:実行順序を定義します(テストの前にビルド)
- パッケージの依存関係:内部パッケージ間の関係を考慮します
- 並列実行:独立したタスクを同時に実行します
- トポロジカル順序:依存関係に沿った正しい順序でタスクを実行します
3. インテリジェントなキャッシュ
Turborepo は入力に基づいてタスクの出力をキャッシュします。
- ローカルキャッシュ:出力をローカルマシンに保存します
- リモートキャッシュ:チームや CI 間でキャッシュを共有します(Vercel またはカスタム)
- コンテンツベースのハッシュ化:入力が変更された場合にのみ再実行します
- キャッシュの復元:キャッシュからタスクを即座に完了します
4. タスクの出力
キャッシュ対象を定義します。
- ビルド成果物(dist/, build/)
- テスト結果
- 生成ファイル
- 型定義
インストール
前提条件
# Requires Node.js 18+ and a package manager
node --version # v18.0.0+
グローバルインストール
# npm
npm install turbo --global
# yarn
yarn global add turbo
# pnpm
pnpm add turbo --global
# bun
bun add turbo --global
プロジェクトごとのインストール
# npm
npm install turbo --save-dev
# yarn
yarn add turbo --dev
# pnpm
pnpm add turbo --save-dev
# bun
bun add turbo --dev
プロジェクトのセットアップ
新しいモノレポを作成する
公式のサンプルを使用します。
npx create-turbo@latest
対話形式のプロンプトで、次の項目を確認されます。
- プロジェクト名
- パッケージマネージャー(npm/yarn/pnpm/bun)
- サンプルテンプレートの選択
手動でのセットアップ
1. ワークスペースを初期化する:
// package.json (root)
{
"name": "my-turborepo",
"private": true,
"workspaces": ["apps/*", "packages/*"],
"scripts": {
"build": "turbo run build",
"dev": "turbo run dev",
"test": "turbo run test",
"lint": "turbo run lint"
},
"devDependencies": {
"turbo": "latest"
}
}
2. ディレクトリ構造を作成する:
my-turborepo/
├── apps/
│ ├── web/ # Next.js app
│ └── docs/ # Documentation site
├── packages/
│ ├── ui/ # Shared UI components
│ ├── config/ # Shared configs (ESLint, TS)
│ └── tsconfig/ # Shared TypeScript configs
├── turbo.json # Turborepo configuration
└── package.json # Root package.json
3. turbo.json を作成する:
{
"$schema": "https://turbo.build/schema.json",
"globalDependencies": ["**/.env.*local"],
"pipeline": {
"build": {
"dependsOn": ["^build"],
"outputs": [".next/**", "!.next/cache/**", "dist/**"]
},
"dev": {
"cache": false,
"persistent": true
},
"lint": {},
"test": {
"dependsOn": ["build"]
}
}
}
設定(turbo.json)
基本構造
{
"$schema": "https://turbo.build/schema.json",
"globalDependencies": [".env", "tsconfig.json"],
"globalEnv": ["NODE_ENV"],
"pipeline": {
// Task definitions
}
}
パイプラインの設定
依存関係のあるタスク:
{
"pipeline": {
"build": {
"dependsOn": ["^build"],
"outputs": ["dist/**", ".next/**"],
"env": ["NODE_ENV", "API_URL"]
}
}
}
主なプロパティ:
dependsOn:先に実行するタスク["^build"]:依存パッケージの build を先に実行する["build"]:自身の build を先に実行する["^build", "lint"]:依存パッケージの build と自身の lint を実行する
outputs:キャッシュするファイル/ディレクトリinputs:入力の検出を上書きします(デフォルト:追跡対象のすべてのファイル)cache:キャッシュを有効化/無効化します(デフォルト:true)env:出力に影響する環境変数persistent:タスクを実行し続けます(開発サーバー向け)outputMode:出力の表示方法を制御します
タスク依存関係のパターン
トポロジカル(^):
{
"build": {
"dependsOn": ["^build"] // Run dependencies' build first
}
}
通常:
{
"deploy": {
"dependsOn": ["build", "test"] // Run own build and test first
}
}
組み合わせ:
{
"test": {
"dependsOn": ["^build", "lint"] // Deps' build, then own lint
}
}
出力モード
{
"pipeline": {
"build": {
"outputMode": "full" // Show all output
},
"dev": {
"outputMode": "hash-only" // Show cache hash only
},
"test": {
"outputMode": "new-only" // Show new output only
},
"lint": {
"outputMode": "errors-only" // Show errors only
}
}
}
環境変数
グローバル環境変数:
{
"globalEnv": ["NODE_ENV", "CI"],
"globalDependencies": [".env", ".env.local"]
}
タスクごとの環境変数:
{
"pipeline": {
"build": {
"env": ["NEXT_PUBLIC_API_URL", "DATABASE_URL"],
"passThroughEnv": ["CUSTOM_VAR"] // Pass without hashing
}
}
}
コマンド
turbo run
パッケージ全体でタスクを実行します。
# Run build in all packages
turbo run build
# Run multiple tasks
turbo run build test lint
# Run in specific packages
turbo run build --filter=web
turbo run build --filter=@myorg/ui
# Run in packages matching pattern
turbo run build --filter='./apps/*'
# Force execution (skip cache)
turbo run build --force
# Run from specific directory
turbo run build --filter='[./apps/web]'
# Run with dependencies
turbo run build --filter='...^web'
# Parallel execution control
turbo run build --concurrency=3
turbo run build --concurrency=50%
# Continue on error
turbo run test --continue
# Dry run
turbo run build --dry-run
# Output control
turbo run build --output-logs=new-only
turbo run build --output-logs=hash-only
turbo run build --output-logs=errors-only
turbo run build --output-logs=full
turbo prune
モノレポのサブセットを作成します。
# Prune for specific app
turbo prune --scope=web
# Prune with Docker
turbo prune --scope=api --docker
# Output to custom directory
turbo prune --scope=web --out-dir=./deploy
用途:
- Docker ビルド(必要なパッケージのみを含める)
- 特定のアプリをデプロイする
- CI/CD のコンテキストサイズを削減する
turbo gen
モノレポ内でコードを生成します。
# Generate new package
turbo gen workspace
# Generate from custom generator
turbo gen my-generator
# List available generators
turbo gen --list
turbo link
ローカルリポジトリをリモートキャッシュにリンクします。
# Link to Vercel
turbo link
# Unlink
turbo unlink
turbo login
Vercel で認証します。
turbo login
turbo ls
モノレポ内のパッケージを一覧表示します。
# List all packages
turbo ls
# JSON output
turbo ls --json
フィルタリング
パッケージ名でフィルタリング
# Single package
turbo run build --filter=web
# Multiple packages
turbo run build --filter=web --filter=api
# Scoped package
turbo run build --filter=@myorg/ui
パターンでフィルタリング
# All apps
turbo run build --filter='./apps/*'
# Pattern matching
turbo run build --filter='*-ui'
ディレクトリでフィルタリング
# From specific directory
turbo run build --filter='[./apps/web]'
Git でフィルタリング
# Changed since main
turbo run build --filter='[main]'
# Changed since HEAD~1
turbo run build --filter='[HEAD~1]'
# Changed in working directory
turbo run test --filter='...[HEAD]'
依存関係でフィルタリング
# Package and its dependencies
turbo run build --filter='...web'
# Package's dependencies only
turbo run build --filter='...^web'
# Package and its dependents
turbo run test --filter='ui...'
# Package's dependents only
turbo run test --filter='^ui...'
キャッシュ戦略
ローカルキャッシュ
デフォルトで有効で、./node_modules/.cache/turbo に保存されます
キャッシュの動作:
{
"pipeline": {
"build": {
"outputs": ["dist/**"], // Cache dist directory
"cache": true // Enable caching (default)
},
"dev": {
"cache": false // Disable for dev servers
}
}
}
キャッシュをクリアする:
# Clear Turbo cache
rm -rf ./node_modules/.cache/turbo
# Or use turbo command
turbo run build --force # Skip cache for this run
リモートキャッシュ
チームや CI 間でキャッシュを共有します:
1. Vercel にリンクする(推奨):
turbo login
turbo link
2. カスタムリモートキャッシュ:
// .turbo/config.json
{
"teamid": "team_123",
"apiurl": "https://cache.example.com",
"token": "your-token"
}
メリット:
- チーム間でビルドを共有
- CI/CD を高速化
- ビルドの一貫性を確保
- コンピューティングコストを削減
キャッシュシグネチャ
以下の場合、キャッシュが無効になります:
- ソースファイルが変更された場合
- 依存関係が変更された場合
- 環境変数が変更された場合(指定されている場合)
- グローバル依存関係が変更された場合
- タスク設定が変更された場合
入力を制御する:
{
"pipeline": {
"build": {
"inputs": ["src/**/*.ts", "!src/**/*.test.ts"],
"env": ["NODE_ENV"]
}
}
}
ワークスペースのパターン
パッケージの種類
1. 内部パッケージ(packages/*):
// packages/ui/package.json
{
"name": "@myorg/ui",
"version": "0.0.0",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
"scripts": {
"build": "tsc",
"dev": "tsc --watch",
"lint": "eslint ."
}
}
2. アプリケーション(apps/*):
// apps/web/package.json
{
"name": "web",
"version": "1.0.0",
"private": true,
"dependencies": {
"@myorg/ui": "*",
"next": "latest"
},
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start"
}
}
依存関係の管理
ワークスペースプロトコル(pnpm/yarn):
{
"dependencies": {
"@myorg/ui": "workspace:*"
}
}
バージョンプロトコル(npm):
{
"dependencies": {
"@myorg/ui": "*"
}
}
共有設定
ESLint 設定パッケージ:
// packages/eslint-config/index.js
module.exports = {
extends: ["next", "prettier"],
rules: {
// shared rules
},
};
TypeScript 設定パッケージ:
// packages/tsconfig/base.json
{
"compilerOptions": {
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
}
}
使用方法:
// apps/web/tsconfig.json
{
"extends": "@myorg/tsconfig/base.json",
"compilerOptions": {
"jsx": "preserve"
}
}
CI/CD との統合
GitHub Actions
name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 18
- name: Install dependencies
run: npm install
- name: Build
run: npx turbo run build
env:
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
TURBO_TEAM: ${{ secrets.TURBO_TEAM }}
- name: Test
run: npx turbo run test
GitLab CI
image: node:18
cache:
key: ${CI_COMMIT_REF_SLUG}
paths:
- node_modules/
- .turbo/
build:
stage: build
script:
- npm install
- npx turbo run build
variables:
TURBO_TOKEN: $TURBO_TOKEN
TURBO_TEAM: $TURBO_TEAM
Docker
FROM node:18-alpine AS base
# Prune workspace
FROM base AS builder
RUN npm install -g turbo
COPY . .
RUN turbo prune --scope=web --docker
# Install dependencies
FROM base AS installer
COPY --from=builder /app/out/json/ .
COPY --from=builder /app/out/package-lock.json ./package-lock.json
RUN npm install
# Build
COPY --from=builder /app/out/full/ .
RUN npx turbo run build --filter=web
# Runner
FROM base AS runner
COPY --from=installer /app/apps/web/.next/standalone ./
COPY --from=installer /app/apps/web/.next/static ./apps/web/.next/static
COPY --from=installer /app/apps/web/public ./apps/web/public
CMD node apps/web/server.js
最適化のヒント
- CI でリモートキャッシュを使用する:
env:
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
TURBO_TEAM: ${{ secrets.TURBO_TEAM }}
- node_modules をキャッシュする:
- uses: actions/cache@v3
with:
path: node_modules
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
- 影響を受けるタスクのみを実行する:
turbo run build test --filter='...[origin/main]'
フレームワークとの統合
Next.js
// apps/web/package.json
{
"name": "web",
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start"
},
"dependencies": {
"next": "latest",
"react": "latest"
}
}
turbo.json:
{
"pipeline": {
"build": {
"outputs": [".next/**", "!.next/cache/**"]
},
"dev": {
"cache": false,
"persistent": true
}
}
}
Vite
{
"pipeline": {
"build": {
"dependsOn": ["^build"],
"outputs": ["dist/**"]
},
"dev": {
"cache": false,
"persistent": true
}
}
}
NuxtJS
{
"pipeline": {
"build": {
"outputs": [".output/**", ".nuxt/**"]
},
"dev": {
"cache": false,
"persistent": true
}
}
}
開発ツールとの統合
TypeScript
{
"pipeline": {
"build": {
"dependsOn": ["^build"],
"outputs": ["dist/**", "*.tsbuildinfo"]
},
"typecheck": {
"dependsOn": ["^build"]
}
}
}
ESLint
{
"pipeline": {
"lint": {
"dependsOn": ["^build"],
"outputs": []
}
}
}
Jest / Vitest
{
"pipeline": {
"test": {
"dependsOn": ["build"],
"outputs": ["coverage/**"],
"cache": true
}
}
}
Prisma
{
"pipeline": {
"db:generate": {
"cache": false
},
"db:push": {
"cache": false
}
}
}
ベストプラクティス
1. モノレポを構成する
my-monorepo/
├── apps/ # Applications
│ ├── web/ # Frontend app
│ ├── api/ # Backend API
│ └── docs/ # Documentation
├── packages/ # Shared packages
│ ├── ui/ # UI components
│ ├── config/ # Shared configs
│ ├── utils/ # Utilities
│ └── tsconfig/ # TS configs
├── tooling/ # Development tools
│ ├── eslint-config/
│ └── prettier-config/
└── turbo.json
2. タスクの依存関係を明確に定義する
{
"pipeline": {
"build": {
"dependsOn": ["^build"]
},
"test": {
"dependsOn": ["build"]
},
"lint": {
"dependsOn": ["^build"]
},
"deploy": {
"dependsOn": ["build", "test", "lint"]
}
}
}
3. キャッシュ設定を最適化する
- ソースファイルではなく、ビルド出力をキャッシュする
- 生成されるすべてのファイルを出力に含める
- キャッシュディレクトリを除外する(例:
.next/cache) - 開発サーバーのキャッシュを無効にする
{
"pipeline": {
"build": {
"outputs": [
"dist/**",
".next/**",
"!.next/cache/**",
"storybook-static/**"
]
},
"dev": {
"cache": false,
"persistent": true
}
}
}
4. 環境変数を適切に使用する
{
"globalEnv": ["NODE_ENV", "CI"],
"pipeline": {
"build": {
"env": ["NEXT_PUBLIC_API_URL"],
"passThroughEnv": ["DEBUG"] // Don't affect cache
}
}
}
5. リモートキャッシュを活用する
- すべてのチームメンバーに対して有効にする
- CI/CD で設定する
- ビルド時間を大幅に短縮
- 大規模なチームでは特に効果的
6. フィルターを効果的に使用する
# Build only changed packages
turbo run build --filter='...[origin/main]'
# Build specific app with dependencies
turbo run build --filter='...web'
# Test only affected packages
turbo run test --filter='...[HEAD^1]'
7. スクリプトを一貫した方法で整理する
ルートの package.json:
{
"scripts": {
"build": "turbo run build",
"dev": "turbo run dev",
"lint": "turbo run lint",
"test": "turbo run test",
"clean": "turbo run clean && rm -rf node_modules"
}
}
8. 永続的なタスクを処理する
{
"pipeline": {
"dev": {
"cache": false,
"persistent": true // Keeps running
}
}
}
よくあるパターン
フルスタックアプリケーション
apps/
├── web/ # Next.js frontend
│ └── package.json
├── api/ # Express backend
│ └── package.json
└── mobile/ # React Native
└── package.json
packages/
├── ui/ # Shared UI components
├── database/ # Database client/migrations
├── types/ # Shared TypeScript types
└── config/ # Shared configs
共有コンポーネントライブラリ
packages/
├── ui/ # Component library
│ ├── src/
│ ├── package.json
│ └── tsconfig.json
└── ui-docs/ # Storybook
├── .storybook/
├── stories/
└── package.json
マイクロフロントエンド
apps/
├── shell/ # Container app
├── dashboard/ # Dashboard MFE
└── settings/ # Settings MFE
packages/
├── shared-ui/ # Shared components
└── router/ # Routing logic
トラブルシューティング
キャッシュの問題
問題:キャッシュが使われるはずなのに、タスクで使用されない
# Check what's causing cache miss
turbo run build --dry-run=json
# Force rebuild
turbo run build --force
# Clear cache
rm -rf ./node_modules/.cache/turbo
問題:キャッシュが大きすぎる
# Limit cache size in turbo.json
{
"cacheDir": ".turbo",
"cacheSize": "50gb"
}
依存関係の問題
問題:内部パッケージが見つからない
# Ensure workspace is set up correctly
npm install
# Check package names match
npm ls @myorg/ui
# Rebuild dependencies
turbo run build --filter='...web'
タスク実行の問題
問題:タスクの実行順序が正しくない
dependsOnの設定を確認する- 依存タスクには
^taskを使用する - タスク名が package.json のスクリプトと一致することを確認する
問題:開発サーバーが起動しない
{
"pipeline": {
"dev": {
"cache": false,
"persistent": true // Add this
}
}
}
パフォーマンスの問題
問題:ビルドに時間がかかりすぎる
# Run with concurrency limit
turbo run build --concurrency=2
# Use filters to build less
turbo run build --filter='...[origin/main]'
# Check for unnecessary dependencies
turbo run build --dry-run
問題:リモートキャッシュが機能しない
# Verify authentication
turbo link
# Check environment variables
echo $TURBO_TOKEN
echo $TURBO_TEAM
# Test connection
turbo run build --output-logs=hash-only
移行ガイド
Lerna からの移行
- Lerna を Turborepo に置き換える:
npm uninstall lerna
npm install turbo --save-dev
- lerna.json を turbo.json に変換する:
{
"pipeline": {
"build": {
"dependsOn": ["^build"]
}
}
}
- スクリプトを更新する:
{
"scripts": {
"build": "turbo run build",
"test": "turbo run test"
}
}
Nx からの移行
- Turborepo をインストールする:
npm install turbo --save-dev
- nx.json を turbo.json に変換する:
- targetDefaults を pipeline にマッピングする
- dependsOn の構文を変換する
- キャッシュを設定する
- ワークスペース設定を更新する
- CI/CD スクリプトを移行する
リソース
- ドキュメント:https://turbo.build/repo/docs
- サンプル:https://github.com/vercel/turbo/tree/main/examples
- Discord:https://turbo.build/discord
- GitHub:https://github.com/vercel/turbo
実装チェックリスト
Turborepo をセットアップする際は、次の手順を実施します。
- Turborepo をグローバルまたはプロジェクト単位でインストールする
- ワークスペース構造(apps/, packages/)をセットアップする
- パイプライン構成を含む turbo.json を作成する
- タスクの依存関係(build、test、lint)を定義する
- 各タスクのキャッシュ出力を構成する
- グローバル依存関係と環境変数をセットアップする
- リモートキャッシュ(Vercel またはカスタム)に接続する
- CI/CD 統合を構成する
- 大規模リポジトリ向けのフィルタリング戦略を追加する
- チーム向けにモノレポ構造をドキュメント化する
- コード生成(turbo gen)をセットアップする
- turbo prune を使用した Docker ビルドを構成する
- ローカルでキャッシュの動作をテストする
- CI でリモートキャッシュを確認する
- 並行処理の設定を最適化する