logo

Next.js 14 から 16 へアップグレードした

Blog Eyecatch

2026.4.20

アップグレードした動機

このブログは Next.js 14 で作って
運用してきたのですが、
ついに Next.js 16 が出たので、
勉強も兼ねてアップグレードすることにしました。

せっかくなので、モダンな機能も取り入れたい。
具体的には Server Components の使い方を
もう少し整理して、
新しい Cache Components の仕組みも
試してみたいなと。

ついでに、ずっと気になっていた
JavaScript と TypeScript の混在状態も
この機会に TypeScript に統一することにしました。

事前準備として掃除から

いきなりアップグレードするのではなく、
まずは掃除から始めました。

package.json を見直したら、
axiosreact-markdownimage-size
unist-util-visit は、
実は import している場所が
一つもない状態でした。
これらをまとめて削除。

また jsconfig.jsontsconfig.json
両方存在していたので、
パスエイリアスを tsconfig.json に寄せて
jsconfig.json は削除。

こういう地味な掃除を先にやっておくと、
アップグレード後のトラブルが減るはずです。

本体のアップグレード

ここからが本番。
Next.js 公式の codemod を使うと、
破壊的変更の大部分を自動で変換してくれます。

npx @next/codemod@canary upgrade latest

このコマンド一つで、
nextreactreact-dom が最新に上がります。
加えて、Next.js 16 の大きな変更点である
「params が Promise になる」というやつも
別の codemod で一括変換できました。

next lint コマンドも廃止されたので、
こちらも codemod で ESLint CLI に移行。
Flat Config に切り替わります。

TypeScript への全面移行

小規模プロジェクトなので、
ファイルを一気に .ts / .tsx にリネームする
ビッグバン方式で移行しました。

全 18 ファイルを git mv でリネームしつつ、
各コンポーネントに props の型を付与。
tsconfig.jsonstrict: true に変更。

記事データの型として PostPostFrontmatter
共通の場所に定義して、
複数のコンポーネントから import する形に整理しました。

Next.js 16 からは next typegen
PageProps<"/blog/[slug]"> のようなルート型を
自動生成してくれるので、
params の型付けもすごく楽でした。

Cache Components で PPR を実現

Next.js 16 の目玉機能である
Cache Components も試してみました。

next.config.mjscacheComponents: true を有効にし、
キャッシュしたい関数に "use cache" ディレクティブを
付けていくだけ。

結果、/blog/[slug] のページが
動的レンダリングから PPR (Partial Prerendering) に変わり、
全記事がビルド時に
プリレンダリングされるようになりました。

/projects の GitHub API フェッチも
cacheLife("hours") で 1 時間キャッシュに。
これで GitHub のレート制限も気にしなくて済みます。

明示的にオプトインする新しいキャッシュモデル、
個人的にはとても分かりやすくて好みです。
最後まで読んでいただきありがとうございます。