← 記事一覧に戻る

Turborepo キャッシュが効かない・ヒットしない時に確認する5つの原因と対策【outputs / env / remote cache】

はじめに

Turborepo を導入したのにキャッシュが一向にヒットしない、CI で毎回フルビルドが走る、>>> FULL TURBO が出たことがない——そんな経験はありませんか?

Turborepo のキャッシュは正しく設定すれば強力ですが、設定の落とし穴が多く、ハマると原因が見えにくいのが難点です。この記事では、よくある5つの原因と解決策をコード例付きで解説します。


症状チェック:こんな症状はありませんか?

  • turbo build を2回実行しても cache miss が続く
  • ローカルではキャッシュが当たるのに CI では毎回フルビルドになる
  • --remote-only フラグを使ってもリモートキャッシュにヒットしない
  • FULL TURBO のメッセージが出たことがない
  • 環境変数を変えていないのにキャッシュが無効化される
  • README.md を編集しただけでビルドキャッシュが壊れる

原因1: outputs が設定されていない・不正確

症状

turbo build 実行後、同じコードで再実行しても cache miss になる。

原因

Turborepo はタスクの outputs に指定されたファイルを保存・復元することでキャッシュを実現します。outputs が設定されていないと、キャッシュの保存は行われますが、復元時にファイルが展開されません。

// turbo.json(❌ outputs が未設定)
{
  "$schema": "https://turbo.build/schema.json",
  "tasks": {
    "build": {
      "dependsOn": ["^build"]
    }
  }
}

解決策

ビルド成果物のパスを outputs に明示します。

// turbo.json(✅ 正しい設定)
{
  "$schema": "https://turbo.build/schema.json",
  "tasks": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": [".next/**", "dist/**", "out/**"]
    }
  }
}

Next.js なら .next/**、Vite なら dist/** を指定します。** を忘れてディレクトリ名だけ書くと中身が含まれないので注意が必要です。


原因2: env に環境変数が含まれていない

症状

ローカルと CI で異なる環境変数を使っているのに CI でキャッシュがヒットして古いビルド結果が使われる(または逆に、環境変数を変えていないのにキャッシュが毎回ミスする)。

原因

Turborepo 1.10 以降、ビルドに影響する環境変数を env に列挙しないとキャッシュキーに含まれません。逆に、大量の環境変数がキャッシュキーに含まれると、微妙な差異でキャッシュが無効化されます。

// turbo.json(❌ env が未設定)
{
  "tasks": {
    "build": {
      "outputs": [".next/**"]
    }
  }
}

解決策

ビルド出力に影響する環境変数のみを env に列挙します。

// turbo.json(✅ env に必要な変数を列挙)
{
  "tasks": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": [".next/**"],
      "env": ["NEXT_PUBLIC_API_URL", "NEXT_PUBLIC_APP_ENV", "NODE_ENV"]
    }
  }
}

ランタイムのみで使用する環境変数(サーバーサイドのシークレットなど)はキャッシュキーに含まないよう passThroughEnv を使います。

{
  "tasks": {
    "build": {
      "env": ["NEXT_PUBLIC_API_URL"],
      "passThroughEnv": ["DATABASE_URL", "STRIPE_SECRET_KEY"]
    }
  }
}

原因3: inputs にビルドに無関係なファイルが含まれている

症状

README.md.md ファイルを編集しただけでキャッシュが無効化される。

原因

inputs を指定しない場合、Turborepo はパッケージ内の 全ファイル.gitignore 除外分以外)をキャッシュキーの計算対象にします。ドキュメントのみ変更したのにビルドキャッシュが無効化されるのはこのためです。

解決策

ビルドに影響するファイルのみを inputs に指定します。

{
  "tasks": {
    "build": {
      "inputs": [
        "src/**/*.ts",
        "src/**/*.tsx",
        "src/**/*.css",
        "package.json",
        "tsconfig.json",
        "next.config.js",
        "next.config.mjs"
      ],
      "outputs": [".next/**"],
      "env": ["NEXT_PUBLIC_API_URL"]
    }
  }
}

原因4: リモートキャッシュの認証が設定されていない

症状

ローカルではキャッシュが当たるが、CI(GitHub Actions 等)では毎回フルビルドが走る。

原因

Turborepo のリモートキャッシュ(Vercel Remote Cache)を使うには、認証トークンとチーム名の設定が必要です。これがないとローカルのファイルシステムキャッシュしか使われません。

解決策

Vercel ダッシュボードでトークンを取得し、CI の環境変数に設定します。

# Vercel CLI でリンク(ローカル確認用)
npx vercel login
npx vercel link

GitHub Actions での設定例:

# .github/workflows/ci.yml
name: CI

on: [push, pull_request]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'

      - name: Install dependencies
        run: npm ci

      - name: Build
        run: npx turbo build
        env:
          TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
          TURBO_TEAM: ${{ vars.TURBO_TEAM }}

TURBO_TOKEN は Vercel のアカウント設定 → Tokens から作成します。TURBO_TEAM はチームのスラッグ(例: my-team)です。個人アカウントの場合は TURBO_TEAM は不要です。

注意: TURBO_TOKEN はシークレット情報なので、GitHub Secrets に保存し、.env ファイルや turbo.json にハードコードしないでください。


原因5: タスクの dependsOn が間違っている

症状

一部のパッケージのビルドキャッシュは当たるが、特定のパッケージだけ毎回リビルドされる。

原因

dependsOn の設定ミスにより、Turborepo が依存グラフを正しく解決できていない場合があります。^build は「依存パッケージの build タスクが完了してから実行」を意味しますが、書き忘れると並列実行になり、依存パッケージのビルド結果が揃う前にタスクが始まってキャッシュが無効化されます。

// ❌ 依存パッケージのビルドを待たずに実行してしまう
{
  "tasks": {
    "build": {
      "outputs": ["dist/**"]
    }
  }
}

解決策

// ✅ 依存パッケージが先にビルドされることを保証
{
  "tasks": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": ["dist/**"]
    }
  }
}

モノレポで packages/uiapps/web の順でビルドが必要な場合、"dependsOn": ["^build"] があることで Turborepo が正しい順序でタスクを実行し、キャッシュも適切に機能します。


キャッシュヒットの確認方法

問題の切り分けには以下のコマンドが役立ちます。

# キャッシュの詳細ログを表示
npx turbo build --verbosity=2

# ドライランでキャッシュ状態を確認(実際には実行しない)
npx turbo build --dry-run

# リモートキャッシュのみ使用して確認
npx turbo build --remote-only

cache hit が表示されればキャッシュが機能しています。cache miss が続く場合は、--verbosity=2 で詳細ログを確認し、どのファイルや環境変数がハッシュを変化させているか特定してください。


まとめ

症状 原因 対策
毎回フルビルド(ローカル) outputs 未設定 ビルド成果物のパスを設定
環境変数でキャッシュが壊れる env の設定ミス ビルドに影響する変数のみ列挙
md変更でキャッシュ無効化 inputs 未設定 ソースファイルのみを指定
CI で毎回フルビルド TURBO_TOKEN 未設定 CI 環境変数にトークンを設定
特定パッケージのみリビルド dependsOn ミス "^build" の記述を確認

Turborepo のキャッシュ設定は最初の一手間がかかりますが、正しく設定すれば CI のビルド時間を大幅に削減できます。FULL TURBO が出た瞬間の達成感はぜひ体験してみてください。