Next.js 16.4が、2026年10月6日(米国時間)に公開されました。npmへの公開は日本時間の10月7日です。この記事は、16系で動いている業務システムやサイトを保守している方に向けて、「16.4に上げると何が変わるのか」「Cache Componentsへの切り替えをいつ、どこから始めるか」を判断できるように整理したものです。
16.4のいちばん大きな変化は、新機能そのものより方針の転換です。公式ブログは、16.4からCache Componentsを「すべてのNext.jsアプリにとって最良の選択」として推奨し、Next.js 17では既定で有効になると書いています。
先に、要点をまとめます(2026年10月9日確認)。
- 16.4は機能追加のリリースです。10月9日時点で、9月30日以降に公表されたNext.jsの脆弱性はなく、セキュリティ対応として急いで上げる必要はありません。16.3.8で動いている当社のサイトは、コードを変えずに16.4.0でbuildが通りました
- Cache Componentsは、有効にした時点で
dynamic・revalidate・dynamicParams などの設定がbuildエラーになります。当社が保守する16.3系のアプリ20件を調べたところ、20件すべてに有効化の前に直す箇所がありました
next upgrade --agent(AIエージェントに更新を任せるコマンド)と更新の通知機能は、公式ドキュメント上は実験的な機能で、本番での利用は推奨されていません。下書きの作成に使い、差分は人が確認します
15系で運用していて、まだ16へ移っていない場合は、こちらの記事より先にNext.js 15から16への移行手順を確認してください。15系のサポートは10月21日で終わります。
Next.js 16.4では何が変わった?
Cache Componentsの推奨化と、それを支える ensureStatic・navigation()・prefetch() の追加、AIエージェント向けの更新機能、Turbopackの改善、React 19.3への対応です。設定を変えなくても効くのはTurbopackの改善で、それ以外は有効にして初めて動くものが中心です。
公式のNext.js 16.4の発表から、既存アプリへの影響で分けると次のようになります。
| 変更 | 状態 | 既存アプリへの影響 |
|---|
| Cache Componentsを全アプリに推奨(17で既定に) | 方針 | create-next-app で作る新規アプリは最初から有効。既存アプリは自分で有効にする |
ensureStatic(ページを静的なまま保つ設定) | 16.4で追加 | Cache Componentsを有効にしたアプリだけで使える |
navigation()・prefetch()(先読みから外す処理) | 16.4で追加 | 同上 |
next upgrade --agent、experimental.agentUpgrade | 実験的 | 更新の通知は既定で 'security' 方針。脆弱性のある版を使っているときに通知が出る |
experimental.agentFeedback | 実験的 | 新規アプリでは既定で有効。既存アプリは設定した場合だけ |
| Turbopackのディスクキャッシュ縮小、サーバー側HMRの遅延、共通ランタイム、CSS Modulesのクラス名短縮 | 安定 | 設定を変えずに入る |
| React 19.3(View Transitionsなどが安定版に) | 安定 | 16.4に上げると入る |
| Rust版React Compiler、ディスクキャッシュの掃除、動的importの遅延コンパイル、ワーカースレッド | 実験的 | experimental で有効にした場合だけ |
ディスクキャッシュについては、公式ブログに「20〜25%小さくなる」と書かれています。当社のサイトで測った数字ではないため、効果は自社の環境で確かめてください。
既存アプリは、16.4にすぐ上げるべき?
セキュリティの観点では急ぐ必要はありません。16.3.8を当てていれば、10月9日時点で公表済みの脆弱性には対応できています。16.4は、通常の保守のタイミングで上げれば十分です。
GitHubのvercel/next.jsで公表されたアドバイザリは、9月30日の7件(16.3.8・15.5.27で修正)が最新です。9月30日のリリースで予告されていた残り2件(Critical・High)は、10月9日時点でまだ公表されていません。公表されれば、16.4系と16.3系の両方に修正版が出るかを確認する必要があります。最新の状況はNext.jsの脆弱性一覧で追記していきます。
状況ごとの判断は次のとおりです。
| いまの状況 | 判断 |
|---|
| 15系で運用している | 先に15.5.27を当て、10月21日までに16へ移る計画を立てる。upgrade latest のcodemodは、10月9日時点では16.4.0を入れる |
| 16.3.8で運用していて、Cache Componentsは使っていない | 次の保守作業で16.4に上げる。Cache Componentsは別の作業として計画する |
| 16.3.7以前の16系 | 16.3.8か16.4.0へ上げる。9月30日の修正が入っていない |
| これから新しく作る | 最初からCache Componentsを有効にして作る |
当社のサイト(このnextjs.zetlinker.com)で試したところ、16.3.8から16.4.0への更新は npm i next@16.4.0 eslint-config-next@16.4.0 だけで、コードの変更なしにbuildが通りました。生成されたページ数は73で変わらず、buildの警告も16.3.8のときと同じ(middlewareの改名を促す警告)でした。ただし、これは1つのサイトでの結果です。独自のwebpack設定や実験的な機能を使っているアプリでは、変更履歴を読んでから上げてください。
Cache Componentsを有効にすると、どこでbuildが止まる?
dynamic・revalidate・fetchCache といったルートの設定、dynamicParams、空の配列を返す generateStaticParams、Edge Runtimeの指定がエラーになります。それを直すと、次に new Date() のような実行のたびに変わる値の扱いで止まります。
公式のCache Componentsへの移行ガイドにある主な項目を、置き換え先と一緒にまとめます。
| 有効化する前の書き方 | 有効化後 | 置き換え先 |
|---|
export const dynamic = 'force-dynamic' | エラー | 削除する。キャッシュしないデータは元々リクエストのたびに実行される |
export const dynamic = 'force-static' | エラー | 削除し、キャッシュしたい処理に 'use cache' と cacheLife を付ける。静的なままにしたいなら ensureStatic |
export const revalidate = 3600 | エラー | 'use cache' と cacheLife('hours') |
export const fetchCache | エラー | 削除し、キャッシュする処理を 'use cache' の中に入れる |
export const dynamicParams | buildが失敗 | 削除する。存在しないパラメーターは notFound() で返す |
generateStaticParams が [] を返す | エラー | 少なくとも1件のパラメーターを返す |
export const runtime = 'edge' | 使えない | Node.jsランタイムに戻す。Edgeが必要な処理はproxyに移す |
fetch の cache: 'force-cache'・next: { revalidate, tags } | 動くが置き換え対象 | 'use cache'・cacheLife・cacheTag |
unstable_cache | そのまま動く | 移行は任意。デプロイをまたいでキャッシュが残る点が 'use cache' と違う |
当社のサイトで cacheComponents: true を設定してbuildすると、7件のエラーで止まりました。内訳は dynamic が3件(robots.ts、記事のプレビュー画面、統計の初期化用API)、revalidate が3件(記事一覧、記事詳細、sitemap.ts)、dynamicParams が1件です。
この7行を外して再びbuildすると、今度は記事詳細の生成で止まりました。原因は、公開日が今日以前かを判定するために、メタデータの生成中に new Date() で今日の日付(日本時間)を求めていたことです。予約投稿のように「今日の日付で表示を切り替える」処理は、Cache Componentsでは、表示のたびに計算するのか、キャッシュするのかを決め直す必要があります。当社のサイトの切り替えはここで止めており、この記事を書いた時点では移行を終えていません。
partialPrefetching を指定しないまま有効にすると、buildの冒頭に「partialPrefetching を true か false に設定してください」という警告が出ました。新しく有効にするなら、公式の案内どおり両方を true にします。
// next.config.ts
import type { NextConfig } from 'next'
const nextConfig: NextConfig = {
cacheComponents: true,
partialPrefetching: true,
}
export default nextConfig
有効化の前に、直す箇所をどう洗い出す?
次のスクリプトを、アプリのルート(app か src/app がある階層)で実行します。ファイルは変更せず、有効化するとエラーになる箇所と、置き換えを検討する箇所を一覧にします。
当社が保守する16.3系のアプリ20件で実行し、さらにこのサイトでは、スクリプトの出した7行とbuildのエラー7件が一致することを確かめてから掲載しています。コメントの中に書かれた revalidateTag(...) を拾う誤検出が1件あったため、コメント行は対象から外しています。
#!/usr/bin/env bash
# Next.js 16.4:Cache Components を有効にする前の事前チェック(読み取りのみ)
set -u
SRC="app src"
hit() { echo "■ $1"; echo "$2" | sed 's/^/ /'; echo; }
g() { grep -rnE --include='*.ts' --include='*.tsx' --include='*.js' --include='*.jsx' "$1" $SRC 2>/dev/null | grep -vE '^[^:]+:[0-9]+:[[:space:]]*(//|\*|/\*)'; }
echo "next: $(node -p "require('next/package.json').version" 2>/dev/null || echo '未インストール')"
r=$(grep -nE "cacheComponents|partialPrefetching" next.config.* 2>/dev/null)
echo "cacheComponents: ${r:-未設定}"; echo
r=$(g "export const (dynamic|revalidate|fetchCache)\b")
[ -n "$r" ] && hit "route segment config(有効化するとエラー。use cache / cacheLife へ置き換え)" "$r"
r=$(g "export const dynamicParams\b")
[ -n "$r" ] && hit "dynamicParams(有効化するとbuildが失敗。notFound() で代替)" "$r"
r=$(g "export const runtime\s*=\s*['\"]edge")
[ -n "$r" ] && hit "runtime = 'edge'(Cache Components は Node.js ランタイムが必要)" "$r"
r=$(g "generateStaticParams" | cut -d: -f1 | sort -u | xargs -r grep -lE "return\s*\[\s*\]" 2>/dev/null)
[ -n "$r" ] && hit "generateStaticParams が空配列を返す疑い(有効化するとエラー)" "$r"
r=$(g "cache:\s*['\"]force-cache|next:\s*\{[^}]*(revalidate|tags)")
[ -n "$r" ] && hit "fetch のキャッシュ指定(use cache + cacheLife / cacheTag へ移す)" "$r"
r=$(g "unstable_noStore|noStore\(\)")
[ -n "$r" ] && hit "unstable_noStore(不要になる。削除候補)" "$r"
r=$(g "revalidateTag\([^,()]*\)")
[ -n "$r" ] && hit "revalidateTag の1引数呼び出し(非推奨。updateTag か第2引数を指定)" "$r"
r=$(g "unstable_cache\(" | cut -d: -f1 | sort -u)
[ -n "$r" ] && hit "unstable_cache(そのまま動く。デプロイをまたいで残る点が use cache と違う)" "$r"
r=$(g "(cookies|headers)\(\)" | grep -E "/(page|layout)\.(t|j)sx?:" )
[ -n "$r" ] && hit "page / layout で cookies()・headers() を読む(Suspense で囲む候補)" "$r"
r=$(g "useSearchParams\(" | cut -d: -f1 | sort -u)
[ -n "$r" ] && hit "useSearchParams を使うクライアントコンポーネント(Suspense が必要)" "$r"
20件で実行した結果、項目ごとに該当したアプリの数は次のとおりでした。
| 検出した項目 | 該当したアプリ(20件中) |
|---|
dynamic・revalidate・fetchCache | 18件 |
dynamicParams | 16件 |
useSearchParams を使うクライアントコンポーネント | 14件 |
unstable_cache | 7件 |
空の配列を返す generateStaticParams | 7件 |
fetch のキャッシュ指定 | 3件 |
runtime = 'edge'(いずれもOG画像などのルートハンドラー) | 2件 |
page・layoutでの cookies()・headers() | 1件 |
結果の読み方は次のとおりです。
- 有効化するとbuildが止まる項目:route segment config、
dynamicParams、runtime = 'edge'、空の generateStaticParams。有効化の前に置き換え方を決めます
- 置き換えを検討する項目:
fetch のキャッシュ指定、unstable_noStore、unstable_cache、1引数の revalidateTag。unstable_cache はそのまま動くので、後回しにできます
- スクリプトでは拾えない項目:
new Date()・Date.now()・Math.random() のような実行のたびに変わる値です。当社のサイトで止まった new Date() は、ライブラリの関数の中にあり、メタデータの生成から呼ばれていました。ファイル名で絞るgrepでは見つからなかったため、next build --debug-prerender を実行して呼び出し元を特定します
有効化は、どの順番で進める?
16.4への更新、事前チェック、有効化と一時的な除外、ルートごとの切り替え、最後に ensureStatic での固定、の順に進めます。アプリ全体を一度に切り替えず、buildが通る状態を保ちながら1ルートずつ進めます。

- 16.4に上げる:まずCache Componentsを有効にしないまま16.4に上げ、buildと画面を確認します。更新と切り替えを分けておくと、不具合が出たときにどちらが原因か切り分けられます
- 事前チェックを実行する:上のスクリプトで、有効化すると止まる箇所を一覧にします
- 有効化し、まだ直さないルートを一時的に除外する:
cacheComponents と partialPrefetching を有効にしてから、公式のcodemodで全ページに instant = false を付けます(npx @next/codemod@canary cache-components-instant-false ./src/app)。src を使っていないアプリは ./app です。公式ドキュメントによると、パスを間違えても失敗にならず「0 ok」と表示されるだけなので、処理されたファイル数を確認します
- ルートごとに切り替える:
instant = false を1つ外し、出てきたエラーを 'use cache' か <Suspense> で直します。new Date() のような値は、instant = false を付けていても止まるため、ここより前に直す必要があります
- 静的にしたいページを固定する:問い合わせ前の説明ページや記事のように、リクエストのたびにサーバーで描画する必要がないページには
ensureStatic を付けます
公式は、この作業をAIエージェントに進めさせるためのSkill(next-cache-components-adoption)も用意しています。機能ごとにプルリクエストを分ける進め方と、1つのブランチでまとめて切り替える進め方を選べます。どちらを使う場合も、各ルートで表示が変わっていないかの確認は人が行います。
ensureStaticとnavigation()は、何に使う?
ensureStatic は、静的に配信したいページに後から動的な処理が混ざったとき、buildを失敗させて気づけるようにする設定です。navigation() と prefetch() は、リンクの先読みで読み込む範囲を減らすための関数です。
ensureStatic には 'shell'・'prefetch'・'navigation' の3段階があり、'navigation' がいちばん厳しく、ページ全体をbuild時に作れることを求めます。レイアウトに付けると、その配下のページすべてに効きます。
// app/blog/layout.tsx
export const ensureStatic = 'navigation'
保守の現場で効くのは、改修のときです。たとえば記事のページに、ログインしている人の名前を表示する部品を後から足すと、そのページはリクエストのたびにサーバーで描画されるようになります。ensureStatic = 'navigation' を付けておけば、この変更はbuildの時点でエラーになるため、気づかないまま本番に出ることを防げます。
navigation() は、await navigation() と書いた位置から下の処理を、先読みのときには実行せず、実際に画面を開いたときに実行させる関数です。一覧画面のリンクが画面に入るたびに詳細の全データを先読みしてしまい、サーバーやデータベースへの負荷が気になる場合に使います。
import { navigation } from 'next/cache'
async function History({ id }: { id: string }) {
await navigation() // ここから下は、先読みでは実行しない
const rows = await getHistory(id)
return <HistoryTable rows={rows} />
}
next upgrade --agent とagentUpgradeは、どう扱う?
公式ドキュメント上は実験的な機能で、本番での利用は推奨されていません。当社では、更新作業の下書きを作らせる道具として扱い、作業は別のGitワークツリーで行い、差分とbuildの結果は人が確認してから取り込む方針にしています。
npx next@canary upgrade --agent=latest を実行すると、CLIがいまの版と更新先を判定し、移行ガイドとcodemod、確認の手順をまとめたタスクをAIエージェントに渡します。対話できる端末で実行すると、インストール済みのCodexかClaude Codeを選んで起動でき、別のGitワークツリーで作業するかも選べます。
| 方針 | 動き |
|---|
security(既定) | 脆弱性の影響を受ける安定版のとき、安全な版への更新を案内する |
latest | npmの最新の安定版(canaryのアプリならcanary)へ更新する |
experimental-future | latest に加えて、Cache Componentsのような将来の既定機能の導入まで案内する |
16.4からは、next dev と next build の実行中に更新の通知が出ることがあります。既定の方針は security で、脆弱性のある版を使っているときに通知されます。対話できる端末では「Upgrade now」「Skip」「Skip until next version」から選び、10秒選ばなければ自動でスキップされます。AIエージェントが next build を実行した場合は、最初の通知でコマンドが止まり、更新があることを報告するよう案内されます。同じコマンドを再実行すれば、警告を出したうえで元の作業を続けます。
AIエージェントにbuildを任せている現場では、この「一度止まる」動きを知らないと、原因の分からない中断に見えます。通知を受け取りたくない場合は、next.configで experimental.agentUpgrade: false を設定します。当社では、脆弱性の通知を受け取るために既定の security のままにしておくことを勧めています。
AIエージェントにコードの更新を任せる際の役割分担は、Next.js受託開発でClaude Codeのサブエージェントをどう使うかでも書いています。
サーバーレスの環境で、use cacheは期待どおりに効く?
'use cache' の保存先は、既定ではサーバーのメモリです。リクエストごとに別のインスタンスが処理するサーバーレスの環境では、キャッシュが次のリクエストで使われないことがあり、デプロイのたびに消えます。
公式のuse cacheのドキュメントは、サーバーレスでは実行時のキャッシュがリクエストをまたいで残らないことが多く、セルフホストのサーバーでは残る、と説明しています。Firebase App Hostingも、実行環境はCloud Runのサービスです(当社のバックエンドの設定で確認しました)。
そのため、Cache Componentsに切り替えた後も、データベースへのアクセスを減らす目的で 'use cache' に頼る場合は、次のどれを選ぶかを決めておきます。
- build時に作れるものは作り、静的なページとして配信する(
ensureStatic で固定する)
'use cache: remote' や cacheHandlers で、RedisやKVのような外部の保存先を使う(費用と通信の時間がかかる)
- デプロイをまたいで残したいものは、
unstable_cache か fetch のキャッシュのまま残す
cacheLife と cacheTag の使い分けや、更新したデータをすぐ画面に出す updateTag の使い方は、Next.js 16のuse cache設計にまとめています。
まとめ
- 16.4は、2026年10月6日(米国時間)に公開された機能追加のリリースです。10月9日時点ではセキュリティ修正を含まないため、16.3.8で運用中なら通常の保守のタイミングで上げます
- Cache Componentsは16.4から全アプリに推奨され、17で既定になります。当社が保守する20件のアプリは、すべて有効化の前に直す箇所がありました
- 有効化すると、まずroute segment configなどでbuildが止まり、次に
new Date() のような値で止まります。前者は記事内のスクリプトで、後者は next build --debug-prerender で洗い出します
next upgrade --agent と更新の通知は実験的な機能です。AIエージェントがbuildを実行すると、最初の通知で止まることがあります
Cache Componentsへの切り替えは、ルートの数と、キャッシュをどこに置くかで作業量が変わります。スクリプトの結果を見て、どこから手を付けるか判断がつかない場合は、ご相談ください。ゼットリンカーでは、Next.jsで動いているシステムのコードを読んで切り替えの範囲を洗い出し、手直しと検証、本番への反映までを保守として引き受けています。保守の契約で更新作業をどう扱うかは、Next.js保守運用の費用と契約で整理しています。
※本記事は、2026年10月9日時点のNext.js 16.4の発表、Cache Componentsへの移行ガイド、ensureStatic、コーディングエージェントによる更新、agentUpgradeの各ドキュメント(16.4.0版)と、vercel/next.jsのReleases・Security Advisoriesに基づいています。
技術仕様・対象バージョンは本文と参照先をご確認ください。
最終更新:2026年10月9日