本文へスキップ
タンヴィル・アハメド

フルスタック開発

EOL前に行うNext.js 15から16.4へのアップグレード

Next.js 15から16.4.2へ移行し、2026年10月のセキュリティパッチの適用、非同期リクエストAPIの更新、Partial Prefetchingの導入を行います。

著者:タンヴィル・アハメド・公開 ・約21分で読めます

AIの支援を受けて調査・執筆した記事です。出典へのリンクは以下に掲載しています。

Read this article in English

Next.js 15は、2024年10月21日の初回リリースから2年後の2026年10月21日にサポート終了(EOL)を迎えます(endoflife.date)。この日以降、15.xリリースラインにはバグ修正やセキュリティパッチが提供されなくなります。2026年10月14日のNext.jsセキュリティアップデートで修正された重大なアップストリームの脆弱性も重なり、Next.js 15を運用しているチームは早急な対応を迫られています。本ガイドでは、当面の脆弱性へのパッチ適用、自動codemodによるNext.js 16.4.2へのアップグレード、破壊的なAPI変更やバンドラー変更の解消、そしてPartial PrefetchingとCache Componentsの導入手順を解説します。

2026年10月の期限が重要な理由

バージョン14以降、Vercelは各メジャーリリースに対してActive LTSとMaintenance LTSに分かれた2年間の長期サポート(LTS)スケジュールを採用しています(endoflife.date)。本番環境へのデプロイが想定されているのはstableリリースチャンネルのみです。Next.js 16は2025年10月21日にActive LTSに入り2027年10月までサポートされますが、Next.js 15は2026年10月21日にMaintenance LTSを終了します。

このライフサイクルの節目は、2つの重要なセキュリティアドバイザリの直後に訪れます。2026年10月8日の事前通知に続き、Next.jsチームは定例外の2026年10月14日のセキュリティアップデートを公開し、v16.4.1(Active LTS)とv15.5.28(Maintenance LTS)をリリースしました。15.xの古いマイナーラインにはセキュリティ修正がバックポートされないため、15.0から15.4を使用しているアプリケーションは少なくとも15.5.28へ移行するか、直接16.4.2へアップグレードする必要があります。

10月14日のアップデートでは、3つのアップストリームの脆弱性が修正されています。

  • use cacheにおける重大なリモートコード実行(GHSA-673q-mjm6-r5xr、React GHSA-xqc2-xf4c-x3h3)。 Next.js 16.0.0から16.4.0でCache Componentsを使用しているApp Routerアプリケーションにおいて、use cache関数が複数の型付き配列(Typed Array)を返す場合に影響します。設定による回避策はありません。
  • SVGを用いた画像最適化における重大なリモートコード実行(CVE-2026-96889、GHSA-2464-fhr4-w9xw)。 sharp経由で使用されるlibrsvg(2.63.2未満)のメモリ脆弱性により、glibcベースのLinuxシステムでSVG画像を処理する際にリモートコード実行につながる可能性があります。Next.js 10.0.0から15.5.27および16.0.0から16.4.0が影響を受けます。15.5.28または16.4.1+へアップグレードすると、sharp 0.35.5以降が導入されます。
  • Server Actionsにおける高深刻度のサービス拒否(DoS)(GHSA-p3m5-59mp-jv5r、React GHSA-h3gv-c5rc-p453)。 1つ以上のServer Actionを公開しているApp Routerアプリケーション(13.0.0から15.5.27および16.0.0から16.4.0)に対し、細工されたリクエストを送ることで過剰なCPU使用率を引き起こし、プロセス内のリクエスト処理をブロックさせることができます。

これらの修正は、2026年9月30日のセキュリティリリース(v16.3.8およびv15.5.27)に続くものです。9月30日のリリースでは、images.remotePatterns設定時の高深刻度のサーバーサイドリクエストフォージェリ(SSRF)、ルート間のキャッシュポイズニング(CVE-2026-94484、GHSA-4jqv-mc3x-m676)、ネストされた'use cache'におけるルートパラメーターの漏洩(GHSA-h694-7cp9-m8p3)、next devにおけるModel Context Protocol(MCP)のオリジンチェックの脆弱性など、7件の問題が修正されました。さらにその前の9月22日の定例外パッチ(v16.3.6およびv15.5.26)では、next/ogの重大なRCE(GHSA-vcvr-r3jv-pc5j、Next.jsセキュリティアドバイザリページで追跡)も解決されています。

v16への移行を始める前に即日対応の暫定措置が必要な場合は、まずnext@15.5.28に固定してください。そうでなければ、直接next@16.4.2へ移行することで、セキュリティアドバイザリへの対応とActive LTSへの移行を同時に完了できます。

Next.js 16アップグレードcodemodの実行とランタイム依存関係の更新

アプリケーションコードを変更する前に、Next.js 16公式アップグレードガイドに照らしてランタイムとコンパイラのバージョンを確認します。

  • Node.js: 最小バージョンは20.9.0です(Node.js 18のサポートは終了しました)。Node.js 20自体も2026年4月30日にEOLを迎えているため、本番環境ではNode.js 22 LTSまたはNode.js 24 LTSをターゲットにしてください。
  • TypeScript: 最小バージョンは5.1.0です。
  • React: reactとreact-dom(および@types/reactと@types/react-dom)をReact 19にアップグレードします。Next.js 16.4はReact 19.3をサポートしています(Next.js 16.4リリースノート)。
  • ブラウザサポート: Chrome 111+、Edge 111+、Firefox 111+、Safari 16.4+です。

Next.jsは、機械的な変更の大部分を処理する自動codemodを提供しています。プロジェクトルートからメインのアップグレードcodemodと非同期リクエストAPIのcodemodを実行します。

# 1. メインのNext.jsアップグレードcodemodを実行
npx @next/codemod@canary upgrade latest
 
# 2. 同期的なparams、searchParams、cookies()、headers()の呼び出しを変換
npx @next/codemod@canary next-async-request-api .
 
# 3. Next.js 16.4.2と最新のReact 19パッケージに固定
npm install next@16.4.2 react@latest react-dom@latest
 
# 4. ルートに対応したTypeScriptヘルパー型を生成
npx next typegen

upgrade latest codemodは、next.config.tsを更新してexperimental.turbopackをトップレベルのturbopackキーへ引き上げ、next lintスクリプトをESLint CLIへ移行し、非推奨となったmiddlewareの規約をproxyにリネームし、安定化されたAPIからunstable_プレフィックスを除去し、レガシーなexperimental_pprフラグを削除します(Next.js 16アップグレードガイド)。

ワークフローでAIコーディングアシスタントを使用している場合、Next.js 16.4で導入されたエージェント支援アップグレードモードも利用できます(Next.js 16.4リリースノート)。npx next@canary upgrade --agent=latestを実行するとコーディングエージェントが実行するための移行手順とcodemodが準備され、npx @next/codemod@canary agents-mdを実行するとnode_modules/next/dist/docs/内にバンドルされたバージョン一致のドキュメントを参照するようにAGENTS.mdが設定されます。

Next.js 15と16の間の破壊的なAPIおよび設定変更への対応

codemodが完了したら、Next.js 16でv15の非推奨な挙動が削除された箇所を確認します(Next.js 16アップグレードガイド)。

非同期リクエストAPI

Next.js 15ではリクエスト固有のデータへの同期アクセスが非推奨となりましたが、Next.js 16では同期アクセスが完全に削除されました。ページ、レイアウト、ルートハンドラー、opengraph-image、twitter-image、icon、apple-iconに渡されるparamsとsearchParamsは厳密にPromiseとなります。同様に、next/headersからインポートするcookies()、headers()、draftMode()もawaitする必要があります。

動的ルートコンポーネントを更新し、paramsとヘッダーヘルパーの両方をawaitするようにします(npx next typegenで生成されるグローバルなPagePropsヘルパーも使用できます)。

// app/projects/[slug]/page.tsx
import { cookies, headers } from 'next/headers';
 
type ProjectPageProps = {
  params: Promise<{ slug: string }>;
  searchParams: Promise<{ [key: string]: string | string[] | undefined }>;
};
 
export default async function ProjectPage(props: ProjectPageProps) {
  const { slug } = await props.params;
  const searchParams = await props.searchParams;
  const cookieStore = await cookies();
  const headerList = await headers();
 
  const theme = cookieStore.get('theme')?.value ?? 'system';
  const userAgent = headerList.get('user-agent') ?? 'unknown';
  const tab = typeof searchParams.tab === 'string' ? searchParams.tab : 'overview';
 
  return (
    <main data-theme={theme}>
      <h2>Project: {slug}</h2>
      <p>Active tab: {tab}</p>
      <small>Requested by: {userAgent}</small>
    </main>
  );
}

Client Componentsでは、async/awaitの代わりにReactのuse(params)フックを使ってparamsおよびsearchParamsのPromiseをアンラップします。

middlewareからproxyへのリネーム

Next.js 16では、ネットワーク境界における役割を明確にするため、middleware.tsが非推奨となりproxy.tsが導入されました(Next.js 16アップグレードガイド)。プロジェクトのルート(またはsrc/内)にあるファイルをリネームし、proxy関数をエクスポートします。

// proxy.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
 
export function proxy(request: NextRequest) {
  const response = NextResponse.next();
  response.headers.set('x-request-path', request.nextUrl.pathname);
  return response;
}
 
export const config = {
  matcher: ['/dashboard/:path*', '/api/:path*'],
};

設定で以前experimental.middlewarePrefetchを使用していた場合は、キー名をexperimental.proxyPrefetchに変更してください。

デフォルト化されたTurbopackとカスタムWebpack設定

Next.js 16では、--turbopackや--turboフラグを付けなくても、next devとnext buildの両方がデフォルトでTurbopackを実行します(Next.js 16アップグレードガイド)。設定ミスが気づかれないままになるのを防ぐため、next.config.ts内にカスタムのwebpack関数(サードパーティ製プラグインによって注入されたものを含む)が検出されると、next buildは意図的に失敗するようになっています。

カスタムWebpackによるビルド失敗を解消するには、次の3つの方法があります。

  1. カスタムローダーやエイリアスをトップレベルのturbopack設定オブジェクトへ移行します。
  2. next build --turbopackを実行し、明示的にTurbopackを使用してwebpackブロックを無視します。
  3. next build --webpackを実行し、TurbopackをオプトアウトしてWebpackでのバンドルを継続します。

Parallel Routes、削除された機能、デフォルト値の更新

本番ビルドを実行する前に、さらに4つの破壊的変更を確認します(Next.js 16アップグレードガイド)。

  • Parallel Routes(@slot)でのdefault.tsxの必須化。 すべてのParallel Routeスロットに明示的なdefault.jsまたはdefault.tsxフォールバックファイルが必要になり、存在しない場合はnext buildが失敗します。最小限のフォールバックでは、next/navigationのnotFound()を呼び出すか、nullを返します。
  • 削除された機能。 next lintコマンド(およびnext build時の自動リント)、serverRuntimeConfig、publicRuntimeConfig、AMPサポート、レガシーなexperimental_pprフラグはすべて削除されました。CIスクリプトではESLint CLIまたはBiomeを直接使用し、ランタイム設定は標準の環境変数に置き換えてください。
  • 画像キャッシュとセキュリティのデフォルト値。 cache-controlヘッダーを持たないオリジン画像の再検証によるCPUオーバーヘッドを下げるため、images.minimumCacheTTLのデフォルト値が60秒から14400秒(4時間)に引き上げられました。デフォルトの画像品質の上限は75になり、imageSizesから16pxが削除され、ローカルIPの画像最適化はデフォルトでブロックされます。
  • スクロール挙動。 <html>要素にdata-scroll-behavior="smooth"を追加しない限り、ルート遷移時にNext.jsがscroll-behavior: smoothを上書きしなくなりました。

以下は、トップレベルのturbopackキー、新しいCache ComponentsとPartial Prefetchingのフラグ、そして16.4で導入された実験的なコンパイラ改善を組み合わせた、Next.js 16.4.2向けのnext.config.tsの統合例です(Next.js 16.4リリースノート)。

// next.config.ts
import type { NextConfig } from 'next';
 
const nextConfig: NextConfig = {
  cacheComponents: true,
  partialPrefetching: true,
  turbopack: {
    resolveExtensions: ['.mdx', '.tsx', '.ts', '.jsx', '.js', '.json'],
  },
  experimental: {
    turbopackGc: true,
    turbopackRustReactCompiler: true,
  },
  images: {
    minimumCacheTTL: 14400,
  },
};
 
export default nextConfig;

Next.js 16.4では、Turbopackのディスクキャッシュサイズが20〜25%削減され、実験的なガベージコレクター(experimental.turbopackGc)がサポートされています。また、experimental.turbopackRustReactCompilerは、最適化が不要なファイルをスキップし、Client Componentsでの重複したSSR処理を回避することで、メモリ使用量を30%、コンパイル時間を15%削減します(Next.js 16.4リリースノート)。

Next.js 16.4のナビゲーション改善とPartial Prefetchingの導入

Next.js 16.4以降、create-next-appはデフォルトでcacheComponents: trueとpartialPrefetching: trueの両方を有効にします。Next.jsチームは、Next.js 17でフレームワークのデフォルトになるのに先立ち、このモデルを導入することを推奨しています(Next.js 16.4リリースノート)。

プリフェッチ最適化ガイドおよびv0のナビゲーション事例で詳述されているとおり、Partial Prefetchingはルートの読み込みを3つの明確なステージに分割します。

  1. App Shellプリフェッチ(デフォルトの<Link>)。 遷移先URLのパラメーターに依存しない、共有の静的シェルとセッション固有のUIをプリフェッチします。
  2. リンク単位のプリフェッチ(<Link prefetch={true}>またはuseRouter().prefetch())。 特定の遷移先URL(/catalog/[id]など)を解決し、paramsやsearchParamsに紐づく静的コンテンツまたはキャッシュ済みコンテンツをプリフェッチします。
  3. ナビゲーション。 ユーザーがリンクをクリックしたときに実行され、キャッシュされていない残りのサブツリーや遅延されたサブツリーをストリーミングします。

await prefetch()とawait navigation()によるステージ制御

コンポーネントツリーが'use cache'を使用している場合、Next.jsは早い段階のプリフェッチステージにキャッシュ済みデータを含めることがあります。ルート内に表示されているリンクが多数ある場合、すべてのキャッシュ済みクエリをプリフェッチするとサーバー負荷が増大する可能性があります。v0の事例では、ステージ境界を調整する前、単純なプリフェッチによって/templates/[id]のプリフェッチリクエストが当初2.9倍に増加しました。

Next.js 16.4では、コストの高いキャッシュ済みサブツリーをリクエスト時の動的処理に強制することなく遅延させるため、next/cacheに2つの関数が追加されました(prefetch()およびnavigation() APIリファレンス)。

  • await prefetch(): コンポーネントサブツリー内のそれ以降の処理を共有App Shellから除外し、明示的なリンク単位のプリフェッチ(<Link prefetch={true}>)または完全なナビゲーション時にのみ実行します。
  • await navigation(): それ以降の処理をApp Shellとリンク単位のプリフェッチの両方から除外します。プリフェッチは代わりに最も近い<Suspense>のフォールバックを受け取り、サブツリーはユーザーが実際にナビゲーションしたときにのみ実行されます。

connection()とは異なり、どちらの関数もサブツリーをリクエスト依存としてマークしないため、これらをawaitした後に呼び出される関数でも引き続き'use cache'を使用できます。

// app/threads/[id]/page.tsx
import { Suspense } from 'react';
import { navigation, prefetch } from 'next/cache';
 
async function fetchThreadSummary(id: string) {
  'use cache';
  return { id, title: `Thread #${id}`, summary: 'Cached summary payload' };
}
 
async function fetchThreadReplies(id: string) {
  'use cache';
  return [
    { id: 'r1', body: 'First cached reply' },
    { id: 'r2', body: 'Second cached reply' },
  ];
}
 
async function ThreadHeader({ id }: { id: string }) {
  await prefetch();
  const summary = await fetchThreadSummary(id);
  return (
    <header>
      <h2>{summary.title}</h2>
      <p>{summary.summary}</p>
    </header>
  );
}
 
async function ThreadReplies({ id }: { id: string }) {
  await navigation();
  const replies = await fetchThreadReplies(id);
  return (
    <ul>
      {replies.map((reply) => (
        <li key={reply.id}>{reply.body}</li>
      ))}
    </ul>
  );
}
 
type ThreadPageProps = {
  params: Promise<{ id: string }>;
};
 
export default async function ThreadPage(props: ThreadPageProps) {
  const { id } = await props.params;
 
  return (
    <section>
      <Suspense fallback={<p>Loading thread header...</p>}>
        <ThreadHeader id={id} />
      </Suspense>
      <Suspense fallback={<p>Loading replies...</p>}>
        <ThreadReplies id={id} />
      </Suspense>
    </section>
  );
}

Playwrightのinstant()テストヘルパーと併用してこれらの境界調整を自動化するには、16.4で導入された公式エージェントスキル(npx skills add vercel/next.js --skill next-bundle-optimizerおよびnext-partial-prefetching-optimizer)をインストールすることもできます(Next.js 16.4リリースノート)。

ensureStaticによるビルド時の静的出力の強制

リクエスト時のレンダリングに決してフォールバックさせてはならないルート(たとえば、トラフィックの多いマーケティング用レイアウトや、Firebase Hostingでの静的Next.jsサイトの配信のような静的サイト)を保守している場合、Next.js 16.4で追加されたensureStatic Route Segment Configが利用できます(ensureStatic APIリファレンス)。

ページやレイアウトからensureStaticをエクスポートすると、ルート内のいずれかのコンポーネントがcookies()、headers()、connection()、またはキャッシュされていないデータを読み取った場合にnext buildが失敗します。

// app/docs/layout.tsx
import type { ReactNode } from 'react';
 
export const ensureStatic = 'navigation';
 
export default function DocsLayout({ children }: { children: ReactNode }) {
  return <div className="docs-container">{children}</div>;
}

指定可能な値は、'auto'(デフォルト)、'shell'(App Shellのみが静的である必要がある)、'prefetch'(App Shellとリンク単位のプリフェッチが静的である必要がある)、'navigation'(サーバーレンダリングされるルート全体が静的である必要がある)、またはfalseです。

ビルドの検証とv16.4.2におけるTurbopackの修正

ターゲットバージョンを固定する際は、v16.4.0やv16.4.1にとどめず、ロックファイルがv16.4.2(2026年10月15日リリース)に解決されることを確認してください(Next.jsリリース一覧)。10月14日のセキュリティパッチはv16.4.1で提供されましたが、v16.4.2には本番環境およびハイブリッドルーター向けの重要なTurbopackの安定性修正がいくつか含まれています。

  • 依存関係のエッジが中途半端に破棄された状態で残っていた、Turbopackの2つのガベージコレクションパスを修正(#100209)。
  • turbo-tasksのスナップショット整合性バグ(#100002)および遅延動的インポートのチャンクリスト衝突(#100211)を解決。
  • Pages Routerの開発用モジュールグラフチェイニングをバックポート(#100008)し、標準のNode.jsの挙動に合わせてモジュール解決中のrealpathエラーを無視するように変更(#100217)。

ローカルでクリーンな型チェックと本番ビルドを実行し、すべての動的API呼び出し、Parallel Routeスロット、および静的制約がTurbopack下でパスすることを検証します。

npx next typegen
npx tsc --noEmit
npx next build

ビルドが成功したら、ビルド出力テーブルを確認してensureStaticを指定したルートが静的または部分的に事前レンダリングされたシェルとしてコンパイルされていることを確認し、2026年10月21日のNext.js 15のEOL期限を迎える前に、ロックファイルでnext@16.4.2とsharp@0.35.5(またはそれ以降)が固定されていることを最終確認してください。

参考資料

  • Next.js
  • React
  • TypeScript
  • セキュリティ
  • マイグレーション

Next.jsの静的サイトをFirebase Hostingで公開する

このサイトの構成を解説します。Next.jsの静的エクスポートをFirebase Hostingで配信し、URL・キャッシュ・SEOメタデータの整合性をとる方法です。

フルスタック開発, 約5分で読めます