開発

Turborepoとは:2.11系のturbo.json設定・キャッシュ共有・CI高速化を実装で解説

Turborepoとは:2.11系のturbo.json設定・キャッシュ共有・CI高速化を実装で解説

Turborepoは、Vercelが開発しているJavaScript・TypeScriptのモノレポ向けビルドシステムです。2026年9月24日時点のnpm最新版は2.11.3で、2.11では実験的ながらRust・Python・Goのワークスペースも扱えるようになりました。この記事では、create-turboによる雛形の作成、turbo.jsonのtasks定義、–filterと–affectedで変更分だけを走らせる方法、Remote Cacheの共有と署名、GitHub ActionsとDockerでの組み込み方を設定例つきで整理します。最後に、Turborepoを入れてよいリポジトリの条件と、Nxや素のワークスペースで足りる場面も言い切ります。

まとめ:Turborepo導入前に決めるタスク定義とキャッシュ共有の範囲

Turborepoが速くするのは、パッケージマネージャのインストールではなく、build・test・lintといったタスクの実行です。入力が変わっていないタスクは実行せず、前回の出力とログを復元します。効果の大きさは、turbo.jsonのoutputsとenvをどれだけ正確に書けるかで決まります。

導入の順番は3段です。まずturbo.jsonにtasksを定義してローカルキャッシュを効かせる。次にCIで–affectedを使い、変更の影響を受けたパッケージだけを走らせる。Remote Cacheでチームとキャッシュを共有するのは最後で、ここで署名とログの扱いを決めます。

2.0で設定キーがpipelineからtasksに変わっています。検索で見つかる日本語の手順にはpipelineのままのものが残っているので、書き写す前にキー名を確認してください。

Turborepoの定義と2.11系で広がった対応範囲、Turbopackとの違い

名前が似た製品が同じVercelにあるため、まず対象を固定します。

Vercel製のモノレポ用ビルドシステムと2.11.3時点の版の位置

Turborepoはタスクランナー兼キャッシュ層です。ソースはGitHubのvercel/turborepoリポジトリで公開され、npmパッケージ名はturbo。npm registryの記録では、2.11.0が2026年9月18日、2.11.3が9月22日に公開されました。直近のマイナー版は2.9が2026年3月、2.10が6月、2.11が9月と、約3か月間隔で出ています。

各パッケージのpackage.jsonにあるscriptsを、依存関係の順序に沿って並列に実行する。これが基本動作です。何を実行するかはscriptsのまま、実行順とキャッシュの規則だけをturbo.jsonに書きます。

2.11のRust・Python・Go対応とproduction pruneの追加内容

Turborepo 2.11の公式リリースノートによると、Cargoワークスペース、uvワークスペース、go.workを実験的に認識します。turbo.jsonのfutureFlagsexperimentalCargoWorkspacesexperimentalPythonWorkspacesを有効にする方式で、JavaScriptのパッケージからRustのビルドにdependsOnを張る書き方も示されました。

同じ版で、最初のタスクが始まるまでの時間が2.9比で最大4倍短くなり、1,037パッケージのリポジトリで45%改善したと公表されています。package.jsonのdevEngines.packageManagerの読み取りと、turbo prune --productionも追加されました。多言語対応は実験扱いなので、本番のCIでは当面JavaScript・TypeScriptのタスクに絞るのが無難です。

TurbopackやHotwireのTurboと取り違えないための切り分け

Turbopackは、Next.jsに組み込まれたバンドラです。1つのアプリ内でモジュールをまとめる層を担い、Turborepoは複数パッケージのタスクを束ねる層を担います。両者は併用でき、Next.jsアプリをTurborepoで管理しつつ、そのビルドの中でTurbopackが動く構成は普通です。Turbopack側の設定はTurbopackとNext.js 16での設定と移行判断で扱っています。

RailsのHotwireにある「Turbo」は、ページ遷移を速くする別のライブラリです。文書では「Turborepo」と正式名で書き、CLIだけturboと書き分けてください。

create-turboとturbo.jsonで雛形を作り、タスクを定義する手順

新規と既存で入り口が違います。新規なら雛形から、既存ならturboを足すだけです。

create-turboでの新規作成と既存リポジトリへのturbo追加コマンド

新規はnpx create-turbo@latestで、apps配下にアプリ、packages配下に共有パッケージを置いた構成が生成されます。既存のワークスペースに足す場合は、公式のインストール手順どおりリポジトリのdevDependenciesに入れます。

# npm workspaces の場合
npm install turbo --save-dev

# pnpm の場合(ルートへの追加を明示)
pnpm add turbo --save-dev --ignore-workspace-root-check

# 動作確認:実行計画だけを JSON で出す
npx turbo run build --dry=json

グローバルインストールもできますが、版をリポジトリ側に固定しておくとCIとローカルの差が出ません。2.11時点で公式に対応するパッケージマネージャはnpm・pnpm・yarn・bunに、nubとaubeを加えた6種です。pnpmを選ぶ場合の前提はpnpmの共有ストアとモノレポ運用、版の固定はcorepackによるpnpmのバージョン管理を参照してください。

turbo.jsonのtasks・dependsOn・outputsを書く最小構成の例

最初に書くのはbuild・test・lint・devの4タスクで足ります。turbo.jsonの設定リファレンスに沿った最小構成を示します。

{
  "$schema": "https://turborepo.dev/schema.json",
  "tasks": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": ["dist/**", ".next/**", "!.next/cache/**"],
      "env": ["NEXT_PUBLIC_API_URL"]
    },
    "test": {
      "dependsOn": ["^build"],
      "outputs": ["coverage/**"]
    },
    "lint": {},
    "dev": {
      "cache": false,
      "persistent": true
    }
  }
}

^build^は「依存先パッケージのbuildを先に終わらせる」という意味で、packages配下のUIライブラリをapps配下より先にビルドさせます。outputsを書き忘れたタスクは、ログだけが復元されて成果物は復元されません。キャッシュヒットと表示されたのにdistが空、という症状の原因はほぼここです。

envModeのstrict既定で変数が消える失敗とenv・globalEnvの区別

turbo.jsonのenvModeは既定がstrictで、envglobalEnvに書いていない環境変数はタスクから見えません。ローカルでは動くのにCIだけAPIのURLが空になる、というトラブルの多くはこの既定値から来ています。

書き分けは単純です。特定のタスクのハッシュに効かせたい変数は各タスクのenvへ。全タスクに効かせたい変数はglobalEnvへ。値をハッシュに含めずに渡すだけでよい変数、たとえばCIのトークン類はpassThroughEnvへ。envに書いた変数は値が変わるとキャッシュミスになるので、ビルド結果を実際に変える変数だけに絞ってください。

turbo runの–filterと–affectedによる変更分のビルド設定

モノレポのCIが遅くなる原因は、変更していないパッケージまで毎回テストすることです。turbo runで対象を絞り、変更したパッケージやその影響範囲をビルドするために、–filterと–affectedの指定方法を分けて確認します。

–filterのパッケージ名・ディレクトリ・Gitコミット指定を組み合わせる書き方

turbo runのリファレンスでは、--filterに次の書き方が並んでいます。

  • --filter=ui:パッケージ名で指定
  • --filter=./apps/*:ディレクトリで指定
  • --filter=[HEAD^1]:直前のコミットから変わったパッケージ
  • --filter=@acme/ui...[HEAD^1]:依存関係の展開と変更検知の組み合わせ

実務で最初に覚えるのは、パッケージ名の後ろに付ける...です。--filter=ui...はuiとuiに依存するパッケージをすべて含み、共有コンポーネントを直したときに影響するアプリだけを確かめられます。

–affectedとTURBO_SCM_BASEでのプルリクエスト差分の検証設定

--affected--filter=...[main...HEAD]と同じ意味で、mainとの差分に影響を受けるパッケージとその依存元を対象にします。基準のブランチがmainでない場合は、環境変数TURBO_SCM_BASETURBO_SCM_HEADで上書きします。

# develop ブランチを基準にしている場合
TURBO_SCM_BASE=origin/develop npx turbo run lint test --affected

# 実行されるタスクとハッシュを事前に確認
npx turbo run test --affected --dry=json

差分の計算にはmain側のコミットが必要です。CIでチェックアウトを浅くしすぎると比較ができず、意図より広い範囲が走ります。GitHub Actions側でパス単位の起動制御を組みたい場合は、GitHub Actionsのトリガーとpathsフィルタの設計と役割を分け、ワークフローの起動はpaths、パッケージの選別はTurborepoに任せると重複しません。

–graphと–summarizeで依存グラフと実行結果を記録する運用

--graphはタスクの依存グラフをsvg・html・mermaid・dotで出力します。--summarize.turbo/runsにJSONを書き出し、どのタスクがキャッシュから復元され、どれが実行されたかをハッシュつきで残します。

キャッシュが効かない原因は、2回分のsummaryを並べてハッシュの入力を比べれば特定できます。

ローカルキャッシュとVercel Remote Cacheをチームで共有する設定と署名

ローカルキャッシュは各自の.turbo配下に溜まります。これをCIと開発者全員で共有するのがRemote Cacheです。

Vercel Remote Cacheの料金と認証・チームへの接続手順

Vercel Remote Cacheは2024年12月に無料化され、Remote Cachingの公式ドキュメントでも全プランで無料、Vercelでホスティングしていなくても使えると明記されています。ローカルではnpx turbo loginで認証し、npx turbo linkでリポジトリをチームに紐づけます。

読み書きの権限は--cacheで分けられ、既定はlocal:rw,remote:rwです。開発者の端末はremote:rで読むだけにし、書き込みはCIに限る。この分け方にすると、手元の未コミットの状態から作られた成果物がチームに配られる事故を防げます。

remoteCache.signatureと秘密鍵によるキャッシュ改ざんの検知設定

turbo.jsonに"remoteCache": { "signature": true }を書き、環境変数TURBO_REMOTE_CACHE_SIGNATURE_KEYに秘密鍵を置くと、アップロード時にHMAC-SHA256で署名されます。ダウンロード時の検証に失敗した成果物はキャッシュミスとして扱われ、使われません。

キャッシュは他人が作った成果物をそのまま実行環境へ持ち込む仕組みです。トークンが漏れれば、書き換えた成果物をCIに配れてしまいます。Remote Cacheを有効にするなら、署名は同時に入れるものと決めてください。

ログもキャッシュされる仕様とセルフホストのRemote Cacheを選ぶ条件

Turborepoはタスクのログも成果物として保存します。テストの途中でトークンや接続文字列を標準出力に出していると、それがキャッシュに残り、チーム全員の端末で再生されます。Remote Cacheを入れる前に、ログへ秘密を出していないかをgrepで確かめてください。

成果物を社外に置けない場合は、公開されているOpenAPI仕様に沿ったHTTPサーバーを自前で立て、turbo login --manualで接続できます。ただし保存先の容量と権限管理を自分で持つことになるため、取引先との契約でソースや成果物の外部保存が禁じられている場合に限って選ぶのが妥当です。

GitHub ActionsとDockerでのTurborepo実行とCI構成

ここまでのTurborepoの設定をGitHub ActionsのCIに載せ、Dockerではturbo pruneでアプリ単位のビルドに必要なファイルを絞り込みます。使う環境変数はTURBO_TOKENTURBO_TEAMの2つです。

TURBO_TOKENとTURBO_TEAMを渡すCIワークフローの設定例

公式のGitHub Actionsガイドは、トークンをsecrets、チーム名をvarsから渡す形を示しています。これに–affectedを組み合わせたnpm workspaces向けの例です。

name: CI
on:
  pull_request:
    types: [opened, synchronize]

jobs:
  build:
    runs-on: ubuntu-latest
    timeout-minutes: 15
    env:
      TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
      TURBO_TEAM: ${{ vars.TURBO_TEAM }}
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: npm
      - run: npm ci
      - run: npx turbo run lint test build --affected

fetch-depth: 0はmainとの差分を取るための指定で、公式例のfetch-depth: 2は直前コミットとの比較を前提にしています。Remote Cacheを使わない場合は、.turboディレクトリをactions/cacheで保存する方法も公式に案内されています。キーの設計はactions/cacheのkey設計と復元されない原因の切り分けが詳しく、パッケージのインストールキャッシュとturboのタスクキャッシュは別のキーで持つのが基本です。

turbo prune –dockerによるアプリ単位のイメージ構築例

turbo pruneのリファレンスによると、turbo prune web --dockerout/jsonに必要なパッケージのpackage.jsonだけ、out/fullにソース一式、out直下に絞り込んだロックファイルを出力します。以下のDockerfileは、アプリ単位のDockerイメージを作る構成例です。依存のインストール層とソースのコピー層を分けられるので、ソースだけを直したときにnpm ciの層が再利用されます。

FROM node:20-alpine AS base
WORKDIR /app

FROM base AS prepare
RUN npm install -g turbo@^2
COPY . .
RUN turbo prune web --docker

FROM base AS builder
COPY --from=prepare /app/out/json/ .
COPY --from=prepare /app/out/package-lock.json ./package-lock.json
RUN npm ci
COPY --from=prepare /app/out/full/ .
RUN npx turbo run build --filter=web

2.11の--productionを付けると、devDependenciesからしか参照されないワークスペースパッケージが除外されます。既定はfalseなので、テスト用の内部パッケージを本番イメージに含めたくない場合に明示してください。Dockerのビルドキャッシュ全般の設計はGitHub ActionsでのDockerイメージビルドとキャッシュ設計にまとめています。

Docker内でRemote Cacheを使うときにトークンをイメージへ残さない渡し方

公式のDockerガイドの例は、TURBO_TOKENをARGとENVでビルドステージへ渡しています。この書き方はENVの値がそのステージのイメージに残るため、builderステージをそのままpushする構成では漏えいの経路になります。

pushするのはrunnerステージだけに限るか、BuildKitの--mount=type=secretでRUNの実行中だけ読ませる形に変えてください。

Turborepoを採用してよいリポジトリ条件と、Nxや素のワークスペースで足りる場面

ここは判断を言い切ります。Turborepoは「入れれば速くなる」道具ではありません。

Turborepoを採用してよいのはパッケージ5つ以上かつCIが10分を超える構成

採用を勧めるのは、ワークスペースのパッケージがおおむね5つ以上あり、プルリクエストごとのCIが10分を超えている場合です。この規模になると、変更していないパッケージのテストが待ち時間の大半を占め、–affectedとキャッシュの効果が数字で見えます。

もう1つの条件は、ビルド成果物のディレクトリが揃っていることです。distや.nextのように出力先が決まっていれば、outputsを書くだけで済みます。パッケージごとに出力先がばらばらなら、先にビルド設定を揃えるほうが先決です。

アプリ1つとライブラリ1つの構成ではワークスペースだけで足りる理由

アプリ1つと共有ライブラリ1つ程度なら、npmやpnpmのワークスペース機能だけで十分です。pnpm -r run buildのような再帰実行で順序も守られ、キャッシュがなくても全体のビルドは数分で終わります。

この規模でTurborepoを入れると、turbo.jsonとoutputsとenvの保守が増えるだけで、短縮できる時間はわずかです。envの書き漏れでCIが落ちる新しい失敗の型も抱えます。モノレポにするかどうかの判断自体はモノレポとマルチリポジトリの違いとツールの選び方で先に固めてください。

Nxを選ぶべき場面とTurborepoからの切り替えを検討する境界

Nxは、タスク実行に加えてコード生成やプラグインによる各フレームワーク連携まで持つ、より広い範囲の道具です。Angularを含むプロジェクトをフレームワーク別のプラグインで一括管理したい、という要件があるならNxのほうが合います。比較の詳細はNx monorepoの機能比較と運用の落とし穴で扱っています。

逆に、既存のpackage.jsonのscriptsを変えずに速くしたいだけならTurborepoが軽い選択です。Turborepoにもジェネレーター機能はあり、turbo/genによるパッケージ雛形の生成で足りる範囲なら、Nxへ移る理由にはなりません。

モノレポのCI改善を社内だけで進めにくいときの外部相談の目安

turbo.jsonの設計、Remote Cacheの署名、Dockerイメージの分割は、どれもCI全体の構成と一緒に見直す作業です。パイプラインの前提を整理するならCI/CDの仕組みとパイプライン構成の判断基準が起点になります。

既存システムの保守と並行してCIを組み替える余力が社内にない場合は、保守運用・内製化支援のように、運用を引き受けながら社内へ手順を移していく体制を検討する余地があります。切り戻しの手順を用意したうえでジョブ単位で置き換える進め方なら、本番リリースを止めずに移行できます。

よくある質問

Turborepoの導入検討でよく挙がる質問に、2.11系の仕様を前提に答えます。

Turborepoは無料で使えますか?

無料です。本体はGitHubで公開されたオープンソースで、npmパッケージturboとして導入します。Vercel Remote Cacheも2024年12月に無料化され、全プランで使え、Vercelでのホスティングも不要。成果物を社外に置けない場合はセルフホストという道もあります。

turbo.jsonのpipelineとtasksはどちらを使えばよいですか?

2.0以降はtasksです。1.x系のトップレベルのpipelineキーは2.0でtasksに置き換わりました。古い手順を参考にしている場合は、公式のnpx @turbo/codemod migrateで設定を移行できます。2022年前後に書かれた解説はpipelineのままのことが多いため、書き写す前にキー名と$schemaのURLを確認してください。

キャッシュヒットしたのにビルド成果物が復元されないのはなぜですか?

ほとんどの場合、そのタスクのoutputsに成果物のディレクトリが書かれていません。outputsが空だとログだけが保存されます。--summarizeのJSONで、キャッシュに含まれたファイルを確認してください。

TurborepoとTurbopackは同じものですか?

別の製品です。どちらもVercel製ですが、Turbopackはアプリ内のモジュールをまとめるバンドラ、Turborepoは複数パッケージのタスクを依存順に実行してキャッシュするビルドシステムです。併用でき、競合しません。

pnpm以外のパッケージマネージャでもTurborepoは動きますか?

動きます。2.11時点の公式ドキュメントでは、npm・pnpm・yarn・bunに加えてnubとaubeが対応として挙がっています。2.11ではpackage.jsonのdevEngines.packageManagerの読み取りにも対応しました。選択は、ロックファイルの扱いやワークスペースの機能で決めてかまいません。Turborepo側の設定はどれを選んでもほぼ同じです。

関連記事

資料請求

RELATED POSTS 関連記事