# pnpm と Turborepo のモノレポの GitHub Actions を速くする（astro：528 秒が 30 秒に）

> pnpm と Turborepo のモノレポの CI が遅いのは、新しい VM での pnpm install と、結果が手元にない turbo のタスクがほとんどです。変わったパッケージだけを動かし、turbo にキャッシュを渡し、pnpm のストアを残す。あるいは両方が残るマシンで動かす。astro の CI は GitHub で 528 秒、Skipbox で 30 秒でした。月 6,000 円の定額です。

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 円の定額、実行時間は無制限です。

- astro の CI は GitHub で 528 秒、Skipbox で 30 秒。40 のビルドのタスクとテストを turbo のキャッシュから戻した
- pnpm のストアと turbo の `.turbo` が専用のマシンに残る。Remote Cache の設定も、アーカイブのダウンロードもなし
- 4 vCPU を月 20,000分使うと、GitHub は 約 35,120 円、Skipbox は 6,000 円

**GitHub Actions を月額固定・使い放題に** Skipbox は、アカウント専用のマシンで GitHub Actions のジョブを動かします。何分動かしても月 6,000 円。ジョブが終わっても Docker のレイヤーと依存パッケージのキャッシュが残るので、次のジョブはすぐ始まります。

4 vCPU のランナーを月 20,000分 使うと、GitHub 約 35,120 円 → Skipbox 6,000 円。毎月 約 29,120 円お得。

移行は `runs-on: skipbox` に 1行書き換えるだけです。

[7日間無料で試す](https://app.skipbox.dev/sign-in?ref=g-pnpm-turborepo-monorepo-github-actions-ja)

## モノレポのジョブは、どこで時間を使っているか

| ステップ | 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 のガイド](https://turborepo.dev/docs/crafting-your-repository/constructing-ci)によれば、`turbo run build --affected` はベースのブランチと比べて変わったパッケージのタスクだけを動かします。GitHub Actions では、プルリクエストなら `GITHUB_BASE_REF`、push なら `GITHUB_EVENT_PATH` を読みます。浅いクローンではすべてのパッケージが変わった扱いになるので、履歴ごとチェックアウトします。

```yaml
- uses: actions/checkout@v4
  with:
    fetch-depth: 0
    filter: blob:none
```

`turbo query affected --packages web` で、ジョブそのものを動かすかどうかも決められます。触っていないアプリのジョブなら、インストールごと飛ばせます。

## 2. ジョブより長生きする turbo のキャッシュ

Turborepo は、タスクの結果を[マシンの `.turbo/cache`](https://turborepo.dev/docs/crafting-your-repository/caching) に置きます。GitHub ホストランナーのマシンはジョブの終わりに消えるので、CI ではこのキャッシュが毎回空から始まります。[Turborepo の GitHub Actions のガイド](https://turborepo.dev/docs/guides/ci-vendors/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 のドキュメント](https://pnpm.io/continuous-integration)も、ストアをキャッシュしてもインストールが速くなるとは「限らない」とはっきり書いています。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 を、ワークフローはそのままで動かした結果です（[実在のプロジェクトでの結果](https://skipbox.dev/ja/guides/rust-cache-slow-rust-ci)）。

| | GitHub（公開リポジトリ、4 vCPU・16 GB） | Skipbox の専用のマシン（4 vCPU） |
|---|---|---|
| ジョブ | 528 秒 | **30 秒**（[31 秒](https://github.com/skipbox-dev/astro/actions/runs/43351547473)、[28 秒](https://github.com/skipbox-dev/astro/actions/runs/43351638436)） |
| ビルドのタスク | 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 は 約 35,120 円、Skipbox S は 6,000 円で、毎月 約 29,120 円安くなります。

## 移行は runs-on を 1行書き換えるだけ

```yaml
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
```

1. Skipbox に GitHub でログインする
2. Skipbox の GitHub アプリを入れて、使うリポジトリを選ぶ
3. `runs-on` を書き換えて push する

キャッシュのステップはそのままで構いません。保存したものは、マシンのそばに残ります。

## セキュリティ

- マシンはアカウントごとの専用です。ほかの会社のジョブと同じマシンで動くことはありません。
- ジョブが終わるたびに、ランナーの認証情報、プロセスとコンテナを消し、残したチェックアウトからも git の認証情報、フック、追跡していないファイルを消します。「毎回クリーン」なら、ジョブごとに新しいマシンで動きます。
- 書き込み権限のない人のコード（フォークからのプルリクエストなど）は、使い捨ての VM で動きます。キャッシュは読めますが、書き換えられません。

くわしくは[ジョブの分離のしくみ](https://docs.skipbox.dev/ja/isolation)にあります。

## モノレポで試す

カード不要で、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 更新 · https://skipbox.dev/ja/guides/pnpm-turborepo-monorepo-github-actions
