pnpm と Turborepo のモノレポの GitHub Actions を速くする(astro:528 秒が 30 秒に)
pnpm と Turborepo のモノレポの CI が遅いとき、時間の大半は 2 つのステップです。新しい VM での pnpm install と、結果がその VM にない turbo run build test。直す順番はこうです。変更が触ったパッケージだけを動かす(履歴のあるチェックアウトで turbo run build --affected)。turbo の結果はマシンの .turbo/cache に置かれ、GitHub はジョブのたびにマシンを消すので、ジョブより長生きするキャッシュを渡す(Remote Cache か、actions/cache で .turbo を戻す)。そして pnpm のストアを残す。GitHub のランナーでは、どのキャッシュもジョブごとのダウンロードです。ディスクが残るマシンなら、最初からそこにあります。astro の CI のジョブは GitHub で 528 秒、Skipbox の専用のマシンで 30 秒。残っていた turbo のキャッシュから、40 のビルドのタスクを全部戻しました。
Skipbox は、アカウント専用のマシンでジョブを動かします。pnpm のストア、ツール、チェックアウトの .turbo がジョブのあとも残るので、Remote Cache もキャッシュのキーも要りません。runs-on: skipbox の 1行を書き換えるだけで、月 6,000 円の定額、実行時間は無制限です。
モノレポのジョブは、どこで時間を使っているか
| ステップ | GitHub の新しい VM では |
|---|---|
| チェックアウト | 既定は浅いクローン。--affected には履歴が要るので、全部取る |
| Node と pnpm の用意 | ツールのキャッシュにそのバージョンがなければダウンロード |
pnpm install | ストアをキャッシュのアーカイブから戻す(なければレジストリから)。そのあと全パッケージの node_modules をリンク |
turbo run build | .turbo/cache を戻すか Remote Cache が答えないかぎり、全タスクが動く |
turbo run test | 同じ。プライベートリポジトリの ubuntu-latest なら 2 CPU で |
1. 変わったものだけを動かす
Turborepo の CI のガイドによれば、turbo run build --affected はベースのブランチと比べて変わったパッケージのタスクだけを動かします。GitHub Actions では、プルリクエストなら GITHUB_BASE_REF、push なら GITHUB_EVENT_PATH を読みます。浅いクローンではすべてのパッケージが変わった扱いになるので、履歴ごとチェックアウトします。
- uses: actions/checkout@v4
with:
fetch-depth: 0
filter: blob:none
turbo query affected --packages web で、ジョブそのものを動かすかどうかも決められます。触っていないアプリのジョブなら、インストールごと飛ばせます。
2. ジョブより長生きする turbo のキャッシュ
Turborepo は、タスクの結果をマシンの .turbo/cache に置きます。GitHub ホストランナーのマシンはジョブの終わりに消えるので、CI ではこのキャッシュが毎回空から始まります。Turborepo の GitHub Actions のガイドにある回り道は 2 つです。
- Remote Cache。
TURBO_TOKENとTURBO_TEAMを設定します(Vercel の Remote Cache か、自前のサーバー)。当たるたびに、そこからのダウンロードです。 .turboへのactions/cache。 キーは${{ runner.os }}-turbo-${{ github.sha }}、restore-keysは${{ runner.os }}-turbo-。実行のたびに新しいキャッシュを保存し、リポジトリのほかのキャッシュといっしょに GitHub の 10 GB の枠を使います。
3. pnpm のストアを残す
actions/setup-node の cache: pnpm か、pnpm store path への actions/cache で、pnpm-lock.yaml をキーにストアを戻せます。node_modules は戻らないので、pnpm は全パッケージをリンクし直します。pnpm の CI のドキュメントも、ストアをキャッシュしてもインストールが速くなるとは「限らない」とはっきり書いています。CI では、pnpm は自分で --frozen-lockfile に切り替わります。
4. コアを使う
turbo は独立したタスクを並列に動かし、ビルドやテストのツールもそれぞれワーカーを立てるので、モノレポはあるだけのコアを使います。プライベートリポジトリの ubuntu-latest は 2 つです。
GitHub のランナーのままでできること、そのコスト
- Remote Cache は、サービスとトークンがもう 1 つ増え、当たるたびにネットワークを通ります。
.turboへのactions/cacheは実行のたびにキャッシュを書き、pnpm のストア、Docker のレイヤー、全ブランチのキャッシュと同じ 10 GB を取り合います。7日使われないものは消えます。- 大きいランナーは、GitHub Team か Enterprise Cloud の組織向けで、分課金です。
ディスクが残るマシンが答えになるとき
astro の CI を、ワークフローはそのままで動かした結果です(実在のプロジェクトでの結果)。
| GitHub(公開リポジトリ、4 vCPU・16 GB) | Skipbox の専用のマシン(4 vCPU) | |
|---|---|---|
| ジョブ | 528 秒 | 30 秒(31 秒、28 秒) |
| ビルドのタスク | 40 を実行 | 40 を turbo のキャッシュから戻した |
| テストのタスク | 実行 | turbo のキャッシュから戻した |
専用のマシンには、前のジョブのチェックアウトの .turbo と pnpm のストアが残っていたので、turbo はダウンロードなしで全タスクの結果を見つけました。turbo が結果から戻すのは入力のハッシュが同じタスクだけなので、実際のコミットでは、触ったパッケージだけが動き直し、残りは戻されます。
Skipbox ならモノレポの状態が残る
プランごとに、アカウント専用のマシンが付き、ジョブのあとも残ります。
- pnpm のストアが残ります。
~/.local/share/pnpm/storeに、npm のキャッシュや各ツールの~/.cacheといっしょに。pnpm installはダウンロードせず、ディスクからリンクします。 - turbo のキャッシュが残ります。
turbo.jsonが turbo 2 のもの(tasksがあり、pipelineがなく、"envMode": "loose"でない)なら、チェックアウトの最上位の.turboがジョブのあとも残ります。TURBO_TOKENもキャッシュのステップも要りません。 node_modulesはジョブのたびに消します。 1 つのチェックアウトを Node のバージョンのマトリクスで使い回しても、別の Node 向けにビルドされたネイティブアドオンを読み込むことはありません。- ツールも残ります。
setup-nodeで入れた Node、pnpm 本体、Docker のイメージとレイヤー。
S で、キャッシュに使える容量は GitHub の 7倍以上。マシンの大きさは、ジョブのラベルで選びます。
| ラベル | マシン | プラン |
|---|---|---|
skipbox | 4 vCPU・メモリ 16 GB | S、月 6,000 円 |
skipbox-8x16 | 8 vCPU・メモリ 16 GB | M、月 12,000 円 |
skipbox-16x32 | 16 vCPU・メモリ 32 GB | L、月 23,000 円 |
実行時間は無制限です。4 vCPU を月 20,000分使うと、GitHub は 参考値:2026年11月10日の為替レート・1ドル=158.22円。米ドルの料金を、このレートで円に換算した概算です。、Skipbox S は 6,000 円で、毎月 参考値:2026年11月10日の為替レート・1ドル=158.22円。米ドルの料金を、このレートで円に換算した概算です。安くなります。
移行は runs-on を 1行書き換えるだけ
jobs:
build:
runs-on: skipbox # ubuntu-latest から書き換える
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
filter: blob:none
- uses: pnpm/action-setup@v3
- uses: actions/setup-node@v4
with:
node-version: 22
cache: pnpm
- run: pnpm install
- run: pnpm turbo run build test --affected
- Skipbox に GitHub でログインする
- Skipbox の GitHub アプリを入れて、使うリポジトリを選ぶ
runs-onを書き換えて push する
キャッシュのステップはそのままで構いません。保存したものは、マシンのそばに残ります。
セキュリティ
- マシンはアカウントごとの専用です。ほかの会社のジョブと同じマシンで動くことはありません。
- ジョブが終わるたびに、ランナーの認証情報、プロセスとコンテナを消し、残したチェックアウトからも git の認証情報、フック、追跡していないファイルを消します。「毎回クリーン」なら、ジョブごとに新しいマシンで動きます。
- 書き込み権限のない人のコード(フォークからのプルリクエストなど)は、使い捨ての VM で動きます。キャッシュは読めますが、書き換えられません。
くわしくはジョブの分離のしくみにあります。
モノレポで試す
カード不要で、7日間かジョブの合計 3,000分まで無料です。ビルドのジョブを runs-on: skipbox に替えて 2 回動かし、2 回目のインストールと turbo の行(cached か executing か)を GitHub と並べてください。
よくある質問
モノレポの GitHub Actions が遅い。pnpm install とビルドに時間がかかるのを速くする方法は?
順に 3 つです。変わったものだけを動かす:turbo run build --affected と、履歴のあるチェックアウト(fetch-depth: 0 と filter: blob:none)。ジョブのあとも残る turbo のキャッシュ:Turborepo の Remote Cache か、actions/cache で .turbo を戻す。pnpm のストアを残す:setup-node の cache: pnpm か、ストアのパスへの actions/cache。GitHub の新しい VM では、どれもジョブごとのダウンロードです。ディスクが残るマシンなら、最初からそこにあります。astro の CI は GitHub で 528 秒、turbo のキャッシュと pnpm のストアが残る Skipbox の専用のマシンで 30 秒でした。
pnpm のストアをキャッシュしているのに、pnpm install が遅いのはなぜ?
戻ってくるストアも、新しい VM でダウンロードして展開するアーカイブだからです。そのあと pnpm は、ワークスペースのすべてのパッケージの node_modules をリンクし直します。pnpm 自身の CI のドキュメントも、ストアをキャッシュしてもインストールが速くなるとは限らないと書いています。ストアが最初からマシンのディスクにあれば、ダウンロードがなくなり、残るのはリンクだけです。
Turborepo のキャッシュは GitHub Actions で効く?
キャッシュがジョブより長生きするときだけです。Turborepo はタスクの結果をマシンの .turbo/cache に置きますが、GitHub ホストランナーのマシンはジョブの終わりに消えます。だから CI では Remote Cache(TURBO_TOKEN と TURBO_TEAM。Vercel のものか、自前のサーバー)か、.turbo への actions/cache が要ります。Skipbox の専用のマシンなら、turbo 2 のプロジェクトはチェックアウトの .turbo がジョブのあとも残るので、Remote Cache なしで変わっていないタスクを結果から戻します。
turbo --affected は GitHub Actions で使える?
使えます。Turborepo はプルリクエストでは GITHUB_BASE_REF、push では GITHUB_EVENT_PATH から比べる相手を見つけます。そのために履歴が要り、浅いクローンだとすべてのパッケージが変わった扱いになります。actions/checkout に fetch-depth: 0 と filter: blob:none を付けます。
Turborepo のモノレポで、Skipbox は何を残す?
pnpm のストア、npm と各ツールのキャッシュ、setup-node で入れたツール、Docker のレイヤー、そして turbo.json が turbo 2 のもの(tasks があり、pipeline がなく、envMode が loose でない)ならチェックアウトの最上位の .turbo です。node_modules はジョブのたびに消すので、インストールは毎回ディスクのストアから走ります。turbo がタスクを結果から戻すのは入力のハッシュが同じときだけなので、コミットが触ったものはきちんと動き直します。
試すのにお金はかかる?
かかりません。カード不要で、7日間かジョブの合計 3,000分まで無料です。モノレポのビルドのジョブを runs-on: skipbox に替えて 2 回動かし、2 回目のインストールと turbo のステップを GitHub と比べてください。
2026年11月13日 更新