15.

Next.js 16 への移行|破壊的変更と詰まりどころ

編集

この記事の要点

  • 機械的な書き換えはコードモッドで済ませられる。npx @next/codemod@canary upgrade latest が入口。
  • 最大の破壊的変更は params / searchParams / cookies() の同期アクセス廃止。専用のコードモッドがある。
  • middlewareproxy に改名。ただし Edge ランタイムは proxy では使えない。
  • experimental.ppr は削除。cacheComponents単なる改名ではないので、同時に有効化しない。
  • AMP・next lintserverRuntimeConfig は削除された。使っていれば必ず引っかかる。

バージョン 15 から 16 への移行は、変更点の数が多いわりに一つ一つは機械的です。ただし「動かない理由が分からない」タイプの詰まり方をしやすく、原因の切り分けに時間を取られがちです。この記事では、実際に遭遇する順に並べて対処法を示します。新規に学んでいる人にとっても、古い記事のコードが動かない理由の索引として使えます。

1まずコードモッドを流す

npx @next/codemod@canary upgrade latest

このコマンドが自動でやってくれるのは次のとおりです。

  • next.config の Turbopack 設定を新しい位置へ移す
  • next lint から ESLint CLI への移行
  • middleware から proxy への改名
  • 安定化した API から unstable_ 接頭辞を外す
  • ルートセグメント設定の experimental_ppr を削除する

ただし、これですべてが終わるわけではありません。同期的な params アクセスが残っている場合は、別のコードモッドを追加で実行します。

npx @next/codemod@canary next-async-request-api .

2前提バージョンを上げる

項目要件
Node.js20.9 以上(18 系はサポート対象外)
TypeScript5.1 以上
ブラウザChrome / Edge 111、Firefox 111、Safari 16.4 以上

手動で上げる場合は本体と React をまとめて更新します。TypeScript を使っているなら型定義も忘れずに。

npm install next@latest react@latest react-dom@latest

3同期アクセスの廃止

バージョン 15 で非同期化され、互換のために同期アクセスも残されていた API が、16 で完全に非同期のみになりました。対象は次のとおりです。

  • cookies()headers()draftMode()
  • layout / page / route / defaultparams
  • pagesearchParams
  • opengraph-image / twitter-image / icon / apple-iconparams
// 15 まで(もう動かない)
export default function Page({ params }) {
  const slug = params.slug
}

// 16
export default async function Page({ params }) {
  const { slug } = await params
}

画像生成関数では id も Promise になりました。generateImageMetadata 側の params は同期のままという非対称があるので、両方を書いている場合は注意してください。sitemapid も同様に Promise です。

4Turbopack が既定になったことによる影響

--turbopack は不要になりました。逆に、独自の Webpack 設定を持つプロジェクトで next build を実行すると、設定の不整合を避けるためビルドが失敗します

3 つの選択肢
①そのまま Turbopack で建てる(--turbopack を明示)/②設定を Turbopack 向けに移行する/③--webpack で従来のバンドラを使い続ける。
身に覚えがない場合
自分で書いていなくても、プラグインが webpack オプションを追加していることがあります。依存パッケージを確認してください。

Sass の ~ 接頭辞(@import '~bootstrap/...')は Turbopack では使えません。接頭辞を外すか、turbopack.resolveAlias で吸収します。

5middleware から proxy へ

mv middleware.ts proxy.ts

関数名も proxy に変えます。設定フラグも skipMiddlewareUrlNormalizeskipProxyUrlNormalize のように改名されました。

ここで一点だけ注意が要ります。proxy の実行環境は Node.js に固定されており、Edge ランタイムは使えません。Edge を前提にした処理がある場合は、当面 middleware のまま運用する判断もあり得ます。

6キャッシュ関連の変更

設定の対応関係 experimental.ppr cacheComponents(動作は別物) experimental.dynamicIO cacheComponents experimental.useCache cacheComponents 積極的に採用していなかったなら、置き換えず「消す」のが正解
名前を移すだけの変更に見えて、cacheComponents を有効にすると未キャッシュのデータアクセスがビルドエラーとして噴出する。移行は別作業として計画する。

API 側の変更も押さえておきます。

API変更内容
revalidateTag第 2 引数(cacheLife プロファイル名)が必須になった
updateTag新設。Server Actions 専用で、即座に反映される
refresh新設。クライアントのルーターだけを更新する
cacheLife / cacheTag安定化。unstable_ 接頭辞が不要になった

7削除されたもの

削除対象代替
AMP(next/ampamp 設定)標準機能で置き換える
next lint コマンドと eslint 設定ESLint / Biome を npm スクリプトから直接呼ぶ
serverRuntimeConfig / publicRuntimeConfig環境変数(必要なら connection() 併用)
devIndicators の一部オプション指標表示そのものは残る
unstable_rootParamsnext/root-params
next/legacy/imagenext/image(非推奨)

8気づきにくい挙動の変化

  • 並行ルートに default.tsx が必須:無いとビルドが失敗します。notFound() を呼ぶか null を返すファイルを置きます。
  • スムーススクロールの上書きをやめたhtmlscroll-behavior: smooth を設定していると、遷移時もスムーズにスクロールするようになりました。以前の挙動に戻すには data-scroll-behavior="smooth"html に付けます。
  • next devnext build が同時に実行できる:出力先が分かれました。開発サーバーの出力は .next/dev です。同じプロジェクトでの二重起動はロックで防がれます。
  • ビルド出力から sizeFirst Load JS が消えた:サーバーコンポーネント構成では正確でなかったためです。実測にはブラウザの計測ツールを使います。
  • next dev 時に process.argv'dev' が含まれない:設定ファイルの読み込み回数が減ったためです。判定は NODE_ENV で行います。
  • ESLint がフラット設定を既定にした.eslintrc 形式を使っている場合は移行を検討します。

9エラーから原因を逆引きする

症状おそらくの原因
params の値が取れないawait していない
ビルドが Webpack 設定を理由に落ちるTurbopack が既定になった影響
next lint が無いと言われるコマンドが削除された
revalidateTag で型エラー第 2 引数の不足
middleware が動かないproxy への改名
並行ルートでビルドが失敗するdefault.tsx の不足
画像が 400 を返すクエリ付きローカル画像、またはローカル IP の制限
画質が指定と違うqualities の既定値による丸め
Server Action が見つからない複数インスタンスで暗号鍵が不一致

10移行の進め方

実務では、次の順で進めると切り分けが楽になります。

  1. Node.js と TypeScript を先に上げ、現行バージョンのまま動作を確認する
  2. 本体を更新し、コードモッドを流す
  3. ビルドを通す(Turbopack・非同期 API・並行ルートの 3 点が主な壁)
  4. 削除された機能の使用箇所を潰す
  5. ここまでを本番に出して安定させる
  6. 別作業として cacheComponents の採用を検討する

とくに 6 を 3 と同時にやらないことが重要です。キャッシュモデルの移行は設計変更を伴うため、バージョン更新と混ぜると原因の特定が困難になります。

ここまでで、シリーズはひととおり完結です。個々のトピックは 目次 から辿れます。

編集
Post Share
子ページ

子ページはありません

同階層のページ
  1. 開発環境の構築とプロジェクトの初期構成
  2. App Router のルーティングとファイル規約
  3. レイアウトと特殊ファイルの使い分け
  4. サーバーコンポーネントとクライアントコンポーネント
  5. サーバー側でのデータ取得と並列化
  6. ストリーミングで体感速度を上げる
  7. キャッシュの仕組みと use cache
  8. 再検証の使い分け
  9. フォーム送信とデータ更新の実装
  10. エラーハンドリングとエラー境界
  11. Route Handlers で API を作る
  12. メタデータ API で SEO を整える
  13. 画像とフォントの最適化
  14. 本番ビルドとセルフホスト
  15. バージョン16 への移行と注意点