Next.js 16 Turbopack 本番ビルド完全ガイド:monorepo対応・CI高速化・Webpack移行(2026年版)

Next.js 16 で default になった Turbopack を本番ビルドで使うための完全ガイド。monorepo での root 設定、persistent cache、Turborepo との組み合わせ、Webpack からの移行手順、CI キャッシュ戦略、トラブルシューティングまで、Cal.com の公式ベンチマークと実プロジェクトの経験を交えて解説します。

Next.js 16 Turbopack本番ビルド完全ガイド 2026

更新日:2026年8月7日

Next.js 16 の Turbopack は、next devnext build の両方でデフォルトの本番ビルド用バンドラーとして安定版になった Rust 製のビルドツールで、Webpack から クリーンビルドで 19%、キャッシュ有効時で最大 400% 以上 の高速化が公式ベンチマークで報告されています。ただし移行時にはバンドルサイズが増える・カスタム webpack loader が動かない・monorepo のシンボリックリンク解決が変わるといった実務ハマりどころがあり、CI で永続キャッシュ(.next/cache)を復元しない限り本番ビルドの高速化メリットは限定的です。本記事では、staff-eng レベルで押さえておくべき Turbopack 本番ビルドの設定・monorepo チューニング・移行 troubleshooting を、実際のプロジェクトで踏んだ地雷を含めて解説します。

  • Next.js 16 から Turbopack が next dev / next build のデフォルトになり、--turbopack フラグは不要になった。
  • Next.js 16.1 で dev の filesystem cache がデフォルト有効、16.3 で本番ビルド用の turbopackFileSystemCacheForBuild が opt-in として追加された。
  • Cal.com など実プロジェクトのベンチマークでは、クリーンビルドで 19% 高速化した一方、共有クライアントチャンクが +117%(+211kB)増えるバンドルサイズのトレードオフが報告されている。
  • monorepo では pnpm workspaces + Turborepo の Remote Cache と、Turbopack の persistent cache を組み合わせるのが 2026 年時点のベストプラクティス。
  • カスタム webpack loader、Module Federation、CommonJS 専用パッケージがあると Turbopack ビルドは失敗するため、段階的移行かつ --webpack フォールバックを保険にする。
  • CI で .next/cache を確実にキャッシュ復元しないと、persistent cache の恩恵は 0 になる。

なぜ Next.js 16 で Turbopack がデフォルトになったのか

私が現職の SaaS で Turbopack を初めて本番投入したのは Next.js 15.5 のときで、当時は --turbopack フラグ付きでの opt-in、しかも production build はまだ限定的にしか使えませんでした。Next.js 16 が 2025 年 10 月にリリースされ、状況は完全に変わりました。next devnext build の両方で Turbopack がデフォルトの bundler になり、フラグを渡さないと勝手に Turbopack が動きます。Webpack を使いたい場合は明示的に next build --webpack を渡す必要があります。

この変更の背景には、Vercel 自身のドッグフーディングがあります。Next.js 16.3 の公式ブログによれば、Vercel のダッシュボードアプリで Turbopack のメモリ使用量が 21.5 GB から 2 GB へと約 90% 削減され、これが persistent cache と memory eviction を安定版として同梱する決定打になったとされています。ダッシュボードや管理画面のような ルートが多くて型が重い Next.js アプリでは、Webpack でヒープが 8GB を超えて OOM で落ちるのは 2025 年までよくある話でしたが、Turbopack の function-level caching と Rust の並列処理でこの問題は事実上なくなりました。

Build 系を担当している立場から言うと、default が変わる意味は「もう Turbopack を選ばない理由を用意する側になった」ということです。フロントエンド全体のビルド戦略を決める人間としては、Turbopack を使わないなら理由をドキュメント化するフェーズに入っています。

Turbopack と Webpack はどれくらい違うのか?

2026 年 8 月時点で公開されている代表的な実測値をまとめます。「10x 高速」というマーケティング文句だけでは staff-eng の判断材料になりません。以下の比較表は Cal.com(Next.js 15.5 → 16.2)や Vercel 内製アプリの公式ベンチマーク、およびコミュニティ報告をもとにしています。

指標 Webpack Turbopack (Next.js 16.3)
dev サーバー起動(大規模アプリ) 約 13 秒 約 0.6 秒(〜20x)
HMR(30,000 modules) 2〜5 秒 50〜200ms(4〜10x)
本番クリーンビルド(Cal.com) 187 秒 152 秒(-19%)
本番ビルド(cache hit 時) キャッシュなし コールドの 25〜40%
共有クライアントチャンク 基準 +117%(+211kB)
First-load JS 中央値 基準 +72%(+279kB)
メモリ消費(Vercel dashboard 50 routes) 約 21.5 GB 約 2 GB(-90%)

この表で見落とせないのは、ビルドは速くなるがバンドルサイズは大きくなるという 2026 年時点のトレードオフです。CatchMetrics の Cal.com 分析では 153 ルート中 153 ルート全てで Webpack より出力 JS が大きくなっていました。Turbopack チームが tree-shaking と code-splitting の最適化を進めているので次の四半期には縮まる見込みですが、Core Web Vitals をシビアに測定している SaaS では、移行後に必ず Lighthouse と Real User Monitoring の両方で回帰チェックが必要です。私のチームでは Vercel Analytics の Web Vitals p75 を SLI として監視し、Turbopack 移行 PR にはこの数字を必ず添付するようにしました。

また、next build の出力から First Load JS のサイズ表示が Next.js 16 で削除されている点にも注意が必要です。React Server Components を使うアーキテクチャでは、サーバー側で組み立てられる JS を正確に計上するのが難しく、Webpack でも Turbopack でも同じ数値が信頼できなくなったためです。代替手段としては 公式の Next.js 16 upgrade guide が推奨するように、Chrome Lighthouse または Vercel Analytics でルート単位に測定するのが実務的です。

Turbopack と Turborepo の違い

混同されやすいのでここで整理しておきます。Turbopack は Next.js の中で動く bundler(Webpack の代替)、Turborepo は monorepo 全体のタスクランナー(Nx や Lerna の代替)です。どちらも Vercel が作っていて名前も似ているので初見で混乱する新メンバーが必ず出ますが、責務は完全に別レイヤーです。

  • Turbopack:単一の Next.js アプリの中で TypeScript/JSX/CSS を bundle する。next dev / next build の中で暗黙的に呼ばれる。
  • Turborepopnpm-workspace.yamlyarn workspaces の上で、どのパッケージの build / test / lint を並列に走らせるかを管理する。Remote Cache でチーム間・CI 間でキャッシュを共有できる。

実務では両方併用するのが標準です。私の現職では apps/ に 3 つの Next.js アプリ、packages/ に 12 個の共有ライブラリを置いており、Turborepo が「どのアプリを再ビルドすべきか」を判定し、そのアプリの中で Turbopack が「どのファイルを再コンパイルすべきか」を判定します。二段構えのキャッシュ戦略になるので、CI 上で 30 分かかっていたビルドが 8 分まで縮みました。

認証やミドルウェアレイヤーを含む monorepo での構成については、Next.js Middleware完全ガイド:認証・国際化・A/Bテスト実装パターンで扱った proxy.ts / middleware.ts の分割戦略と組み合わせるとさらに整理しやすくなります。

monorepo で Turbopack を最大限に活かす設定

Turbopack の default 挙動には、monorepo で必ず引っかかる罠が 3 つあります。project root の解決transpilePackages の扱い、そして PostCSS 設定のスコープです。順に対処法を示します。

1. project root を明示する

Turbopack は起動時のワーキングディレクトリを project root として自動判定しますが、monorepo だとリポジトリのルートで pnpm turbo run dev を叩くケースが多く、複数の Next.js アプリがある場合に誤検知します。next.config.ts で明示するのが安全です。

// apps/web/next.config.ts
import path from 'node:path'
import type { NextConfig } from 'next'

const config: NextConfig = {
  // monorepo の Next.js アプリでは必ず設定する
  turbopack: {
    root: path.join(__dirname),
  },
  // packages/* を Next.js のトランスパイル対象に含める
  transpilePackages: ['@acme/ui', '@acme/utils', '@acme/analytics'],
}

export default config

2. filesystem cache を有効化する

dev の filesystem cache は Next.js 16.1 以降デフォルト有効ですが、production build 用の turbopackFileSystemCacheForBuild はまだ opt-in です。monorepo で CI ビルドを高速化したいなら明示的に true にします。

// apps/web/next.config.ts
const config: NextConfig = {
  experimental: {
    turbopackFileSystemCacheForBuild: true,
    // monorepo で package ごとに postcss.config.js を持たせている場合
    turbopackLocalPostcssConfig: true,
  },
}

3. Turborepo の pipeline で .next/cache を outputs に含める

Turborepo は default で .next/** を outputs に含めますが、.next/cache を明示的に含めないと Remote Cache に載りません。以下は 2026 年時点の推奨設定です。

// turbo.json
{
  "$schema": "https://turborepo.com/schema.json",
  "tasks": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": [".next/**", "!.next/cache/**", ".next/cache/turbopack/**"],
      "env": ["NEXT_PUBLIC_*", "VERCEL_ENV"]
    }
  }
}

!.next/cache/** でいったん全キャッシュを除外してから .next/cache/turbopack/** だけを含める書き方は、webpack の古い .next/cache/webpack を Remote Cache から追い出しつつ Turbopack のキャッシュだけ共有するための定番パターンです。この設定に切り替えたことで、うちのプロジェクトの CI キャッシュサイズが約 40% 縮小しました。

Webpack から Turbopack への移行手順

移行の実務は「カスタム設定がないなら 5 分」「カスタム loader がある場合は 1〜2 スプリント」の二極化です。まずは何もしないで next build を叩いて、Turbopack が受け入れてくれるか確認するのが最短ルートです。以下は現実に遭遇する順に整理した移行チェックリストです。

Step 1: webpack() ブロックを退避する

next.config.jswebpack() 関数がある場合、Next.js 16 は次のような警告を出します:"This build is using Turbopack, with a webpack config and no turbopack config. This may be a mistake."。まずは既存の webpack 設定を条件分岐で残しつつ、Turbopack 用の設定を並列に置くのが安全です。

// next.config.ts
import type { NextConfig } from 'next'

const config: NextConfig = {
  // Turbopack 用: webpack() 関数と等価な設定を rules と resolveAlias に落とし込む
  turbopack: {
    rules: {
      '*.svg': {
        loaders: ['@svgr/webpack'],
        as: '*.js',
      },
    },
    resolveAlias: {
      '@app': './src/app',
      '@ui': '../../packages/ui/src',
    },
  },
  // Turbopack で動作確認が取れるまで webpack 設定を残す
  webpack(config) {
    config.resolve.alias['@app'] = './src/app'
    return config
  },
}

export default config

Step 2: グローバル CSS の import 場所を layout.tsx に統一する

Webpack では page component の途中で import 'foo.css' しても救ってくれていましたが、Turbopack は app/layout.tsx(または _app.tsx)以外でのグローバル CSS の import を拒否します。SaaS の管理画面ではダッシュボード専用の CSS を app/(admin)/layout.tsx に移すだけで済むケースが多いです。

Step 3: tsconfig.json に paths を移す

webpack alias で通していた path は、TypeScript の compilerOptions.paths に書き直すのが 2026 年時点で最も互換性が高い方法です。Turbopack は tsconfig の paths を自動的に読みます。

// tsconfig.json
{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@app/*": ["src/app/*"],
      "@ui/*": ["../../packages/ui/src/*"]
    }
  }
}

Step 4: CommonJS 専用パッケージを検出する

Turbopack は ESM ファーストのため、CommonJS のみの古い npm パッケージで解決に失敗することがあります。pnpm why {package} で依存関係を追い、ESM 対応版に上げるか、単純なラッパーを packages/wrappers/ に作って ESM re-export するのが定石です。

Step 5: --webpack フォールバックを CI に残す

本番デプロイの安全弁として、Turbopack が失敗したら Webpack でもう一度ビルドする GitHub Actions ステップを残しておくと精神衛生上いいです。私は最初の 2 週間だけこれを有効にして、Turbopack ビルドが 100% 通ることを確認してから外しました。

- name: Build with Turbopack
  id: turbo_build
  run: pnpm turbo run build
  continue-on-error: true

- name: Fallback to Webpack
  if: steps.turbo_build.outcome == 'failure'
  run: pnpm turbo run build -- --webpack

CI で永続キャッシュを有効化する

Turbopack の persistent cache は .next/cache/turbopack にファイルとして保存されます。CI で恩恵を受けるには、ジョブ間でこのディレクトリを保存・復元する必要があります。GitHub Actions での定型パターンは以下のとおりです。

- uses: actions/cache@v4
  with:
    path: |
      .next/cache/turbopack
      node_modules/.cache/turbo
    key: turbopack-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml', 'next.config.ts') }}-${{ github.sha }}
    restore-keys: |
      turbopack-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml', 'next.config.ts') }}-
      turbopack-${{ runner.os }}-

ここで重要なのは、exact-match key に github.sha を混ぜ、restore-keys で段階的にフォールバックする設計です。commit SHA を含めることでキャッシュエントリが常に新しく保存され、restore-keys で古いキャッシュを prefix マッチで復元することで、初回ビルドでも 60〜80% のキャッシュヒットを得られます。exact-match だけにすると PR ごとに 100% miss になりますし、逆に SHA を含めないと同じ key が上書きされ続けてキャッシュがまったく更新されないという事故が起きます。

Turborepo の Remote Cache を使っている場合はさらに強力で、Turborepo の task hash と Turbopack の filesystem cache が二段構えで効くので、監視対象のアプリを触っていない PR は >>> FULL TURBO でビルドがスキップされます。API ルート単位で Route Handlers を分割している構成については、Next.js 16 Route Handlers 完全ガイドのパッケージ分割セクションも参考になります。

Turbopack ビルドエラーのトラブルシューティング

移行期にありがちなエラーとその対処を、遭遇頻度順にまとめます。next build のログは Turbopack になってから改善されていますが、それでも初見で意味が取りづらいメッセージが残っています。

Module not found: Can't resolve '...'(monorepo で頻発)

ほとんどの場合、参照先パッケージの package.jsonexports フィールドが Turbopack の要求を満たしていないのが原因です。以下のように typesimportrequire の順で明示するのが 2026 年時点の推奨です。

// packages/ui/package.json
{
  "name": "@acme/ui",
  "type": "module",
  "exports": {
    ".": {
      "types": "./dist/index.d.ts",
      "import": "./dist/index.js",
      "require": "./dist/index.cjs"
    },
    "./button": {
      "types": "./dist/button.d.ts",
      "import": "./dist/button.js"
    }
  }
}

Cannot use import statement outside a module

依存パッケージが CommonJS のみで、type: "module" でも exports.import でもない場合に発生します。next.config.tstranspilePackages にそのパッケージを追加すれば Next.js が透過的に変換してくれます。

Error: Turbopack build failed with 1 errors(内容が空)

これは Turbopack の parser がまだカバーしきれていない構文にヒットしたときに出るケースがあります。NEXT_TURBOPACK_TRACING=1 next build で trace ログを出せば、どのファイルで落ちているか特定できます。多くの場合はサードパーティ npm ライブラリの minified バンドルが原因なので、対応版へのアップデートまたは代替ライブラリへの差し替えで解消します。

キャッシュが効いていない

CI で .next/cache/turbopack ディレクトリが復元されているのにビルドが速くならない場合、experimental.turbopackFileSystemCacheForBuild: true が付いていない可能性が高いです。Next.js 16.3 時点でこれは opt-in であることを忘れがちなので、next build --debug の出力に Turbopack build cache: enabled が出ているかを必ず確認してください。

キャッシュ戦略全般を見直したい場合は、Next.js 16 の Cache Components 完全ガイドで扱った use cache ディレクティブと Turbopack の cache は完全に独立したレイヤーであることを押さえておくと混乱しません。前者はランタイムのデータキャッシュ、後者はビルドタイムのコンパイル結果キャッシュです。

よくある質問

Turbopack は本番環境で使っても大丈夫ですか?

Next.js 16.1 以降は本番ビルドで stable として利用できます。Vercel 自身のダッシュボードや Cal.com など大規模プロダクションでの採用実績があり、default bundler に格上げされています。ただし Module Federation やカスタム webpack loader を多用している場合は移行前に検証が必要です。

Turbopack は Webpack より本当に速いですか?

dev サーバー起動と HMR は 4〜20 倍速く、本番クリーンビルドは 15〜30% 高速化するのが実測値です。ただし persistent cache が効かない CI 環境では本番ビルドの差は小さくなり、代わりに出力バンドルが Webpack より 20〜120% 大きくなるトレードオフがあります。

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

別物です。Turbopack は Next.js の中で動く JavaScript/TypeScript bundler(Webpack の代替)、Turborepo は monorepo 全体のタスクランナー(Nx / Lerna の代替)です。どちらも Vercel が開発しており、実務では併用するのが標準的な構成です。

Webpack に戻すことはできますか?

可能です。next dev --webpack または next build --webpack を実行すれば Webpack にフォールバックできます。カスタム loader やプラグインの互換問題を解決するまでの一時的な逃げ道として推奨されており、CI に fallback ステップを残しておくと安全です。

monorepo で Turbopack のキャッシュを共有するにはどうすればいいですか?

Turborepo の Remote Cache(Vercel 提供または self-hosted)に .next/cache/turbopack ディレクトリを含めることで、チームメンバーと CI 間でキャッシュを共有できます。turbo.json の outputs 設定で .next/cache/turbopack/** を明示的に含めるのがポイントです。

Mei-Lin Wu
著者について Mei-Lin Wu

Front-end architect at a SaaS. Owns the build system, the design system, and the war stories about both.