「Next.jsは速い」という評判を聞いて採用したのに、実際のプロジェクトでは開発サーバーの起動が重い、ビルドに時間がかかる、といった実感を持つ方は少なくないはずです。フレームワーク自体の性能と、実際のアプリケーションで体感できる速度の間には、設定や実装次第でギャップが生まれます。
先に、要点をまとめます。
- Next.js 16系はTurbopackの標準採用以降も継続的に高速化しており、2026年8月時点の最新16.3では開発サーバーのメモリ使用量が最大90%、リピートビルドが最大5.5倍高速化しています
- ただしこれらの恩恵の多くは「アップグレードするだけ」で得られる一方、画像最適化・キャッシュ設計・バンドルサイズ管理は依然としてアプリ側の実装で差が出ます
- パフォーマンス改善は闇雲に手を広げるのではなく、Core Web Vitals(LCP・INP・CLS)のどれがボトルネックかを計測してから着手するのが遠回りに見えて最短です
なお、Next.js 16.3の全体像とセキュリティパッチの運用についてはNext.jsのCVE対応は誰がやるのかで、Turbopack安定版化の経緯はNext.js 16.2でTurbopackが安定版にで扱っています。本記事は「実際のアプリケーションでパフォーマンスをどう改善するか」という実装側の観点に絞って整理します。
ただし、フレームワークのアップグレードだけでは解決しない問題が1つあります。それが何かは、記事の後半で詳しく説明します。
Next.js 16系は今どこまで速くなっている?
2026年8月時点の最新版16.3では、開発サーバーのメモリ使用量が最大90%、条件が揃えばリピートビルドが最大5.5倍高速化しています。 これらはコード変更なしでバージョンアップするだけで得られる改善です。
Next.js公式ブログによれば、16.3で導入されたディスクキャッシュとメモリエビクション機能により、長時間の開発セッションでのメモリ使用量が大幅に削減されました。公式の計測例では、大規模なダッシュボードアプリケーションで21.5GBから2GBへ(約90%減)、nextjs.org自体でも4,600MBから840MBへ(約82%減)という改善が報告されています。
ビルド速度についても、変更のないファイルのキャッシュを再利用する仕組みがビルドコマンドにも適用され、CI環境での再ビルドが案件によっては最大5.5倍速くなったとされています。さらに、サーバーサイドレンダリングの内部実装が見直され、負荷時に処理できるリクエスト数が最大22%増加したことも報告されています。
これらの数値はいずれもNext.js公式ブログの計測例であり、実際の改善幅はアプリケーションの規模や構成によって変わります。とはいえ、大きな設定変更を必要とせず「上げるだけ」で恩恵を受けられる点は、保守を後回しにしがちな中小企業のシステムにとって特に価値があります。
バージョンアップだけで解決しないパフォーマンス課題とは?
画像最適化・データフェッチの設計・不要なクライアントJavaScriptの削減は、フレームワークのバージョンに関わらずアプリ側の実装で差が出ます。 ここを見落とすと、最新版にアップグレードしても体感速度が変わらない、という状況になりがちです。
Turbopackの高速化は主に開発体験(ローカルでの起動・ビルド速度)とサーバーサイドの処理効率に効きます。一方で、実際にユーザーが体感する表示速度は、次のような要素に大きく左右されます。
- 画像のサイズ・フォーマットが最適化されているか
- ページに必要なデータをどう取得しているか(直列で待つか、並行して取得するか)
- クライアント側に送られるJavaScriptの量が必要最小限か
つまり「Next.jsは速いフレームワークだから」という理由だけでパフォーマンスを楽観視すると、実装側の見落としがそのままユーザー体験に跳ね返ってきます。
画像最適化はどこまで自動化されている?
next/imageコンポーネントを使えば、サイズ変換・フォーマット最適化・遅延読み込みは自動化されますが、適切なsizes属性の指定とpriorityの使い分けは実装者側の判断が必要です。
Next.jsの画像最適化機能は、画像をリクエストされたデバイスサイズに合わせて自動的にリサイズし、WebP等の最適なフォーマットに変換します。ただし、この自動化にも実装者が意識すべきポイントがいくつかあります。
import Image from 'next/image';
// ファーストビューに表示される画像はpriorityを付ける
export function HeroImage() {
return (
<Image
src="/hero.jpg"
alt="サービス概要を示すヒーロー画像"
width={1200}
height={630}
priority
sizes="(max-width: 768px) 100vw, 1200px"
/>
);
}
priorityを付けない画像はデフォルトで遅延読み込みされます。ファーストビュー(LCP計測の対象になりやすい画像)にpriorityを付け忘れると、Largest Contentful Paintの計測値が悪化しやすくなります。逆に、画面外の画像すべてにpriorityを付けてしまうと、優先度の高い画像と競合してかえって表示が遅くなることもあります。
sizes属性も見落とされがちです。指定しない場合、ブラウザは実際の表示サイズより大きい画像をダウンロードすることがあり、モバイル回線でのLCPに影響します。レスポンシブなレイアウトでは、実際にその画像がどのくらいの幅で表示されるかをブレークポイントごとに指定するのが安全です。
データフェッチの並行化はなぜ重要?
複数のデータ取得を直列(順番待ち)で書くと、それぞれの待ち時間が合算されてページ全体の表示が遅くなります。並行して取得すれば、最も遅い1件分の待ち時間で済みます。
Server Componentsの中で複数のデータソースを扱う際、書き方次第で表示速度に大きな差が出ます。
// 避けたい書き方: 直列実行(待ち時間が合算される)
async function ProductPage({ id }: { id: string }) {
const product = await getProduct(id); // 300ms
const reviews = await getReviews(id); // 250ms
const related = await getRelatedItems(id); // 200ms
// 合計で約750ms待つことになる
}
// 推奨する書き方: 並行実行
async function ProductPage({ id }: { id: string }) {
const [product, reviews, related] = await Promise.all([
getProduct(id),
getReviews(id),
getRelatedItems(id),
]);
// 最も遅い1件(300ms)で済む
}
依存関係のないデータ取得を直列で書いてしまうミスは、機能追加を急いだ際に紛れ込みやすいパターンです。特に複数人・複数のAIエージェントが並行して機能を積み重ねていく開発では、それぞれが個別にawaitを追加した結果、気づかないうちに直列実行の連鎖ができあがっていることがあります。定期的にコードレビューやAIエージェントによる静的な見直しで、不要な直列待ちが無いかを確認する価値があります。
また、ページの一部だけ取得が遅い場合は、Suspenseでその部分を切り出し、残りの部分を先に表示してから遅い部分をストリーミングで後から差し込む設計も有効です。ユーザーは「白い画面で待たされる」体験を避けられ、体感速度が改善します。

クライアントに送るJavaScriptはどう減らせる?
Server Componentsをデフォルトにし、'use client'を本当にインタラクティブな部分だけに限定することで、クライアントに送るJavaScriptの量を最小限に抑えられます。
App RouterのServer Componentsは、サーバー側でレンダリングを完結させ、クライアントにはHTMLだけを送る仕組みです。しかし、コンポーネントツリーの一部に'use client'を付けると、そのコンポーネントとその配下のコンポーネントはすべてクライアント側のJavaScriptバンドルに含まれます。
よくある見落としは、「このボタンだけインタラクティブにしたい」という理由で、ページ全体を含む大きなコンポーネントに'use client'を付けてしまうケースです。
// 避けたい書き方: ページ全体をクライアントコンポーネント化
'use client';
export default function ProductPage() {
const [isOpen, setIsOpen] = useState(false);
return (
<div>
<ProductDetails /> {/* インタラクティブでないのにJSが送られる */}
<ReviewList /> {/* 同上 */}
<button onClick={() => setIsOpen(!isOpen)}>詳細を開く</button>
</div>
);
}
// 推奨する書き方: インタラクティブな部分だけを分離
export default function ProductPage() {
return (
<div>
<ProductDetails /> {/* Server Componentのまま */}
<ReviewList /> {/* Server Componentのまま */}
<ExpandButton /> {/* この部分だけクライアントコンポーネント */}
</div>
);
}
ExpandButtonのような、実際に状態やイベントハンドラを必要とする部分だけを切り出すことで、ProductDetailsやReviewListはサーバー側で完結し、クライアントに送られるJavaScriptの量を抑えられます。ページの規模が大きくなるほど、この切り分けの精度がバンドルサイズに直結します。
実際のボトルネックはどう見極める?
Core Web Vitals(LCP・INP・CLS)を計測し、どの指標が悪化しているかを特定してから対策を選ぶのが遠回りに見えて最短です。 闇雲に「最適化」を試みると、体感速度が変わらないまま実装の複雑さだけが増えることがあります。
改善に着手する前に、まず現状を数値で把握することをおすすめします。Next.jsにはreportWebVitalsという仕組みがあり、実際のユーザー環境での計測値を収集できます。
// app/layout.tsx や専用のクライアントコンポーネントで使用
export function reportWebVitals(metric: { name: string; value: number }) {
// 計測値を分析ツールに送信する
if (metric.name === 'LCP' && metric.value > 2500) {
// LCPが2.5秒を超えている場合の処理
}
}
Googleが公表しているCore Web Vitalsの目安は、LCP(最大コンテンツの表示速度)が2.5秒以内、INP(操作から応答までの反応速度)が200ミリ秒以内、CLS(レイアウトのずれ)が0.1未満です。この3指標のうち、どれが目安を超えているかによって、打つべき対策はまったく異なります。
- LCPが遅い場合: 画像の
priority指定漏れ、フォントの読み込み方式、サーバーレスポンス自体の遅さを疑います
- INPが遅い場合: クライアントJavaScriptの量、重い処理がメインスレッドをブロックしていないかを疑います
- CLSが高い場合: 画像やフォントの読み込みでレイアウトが後から動いていないか(
width/heightの指定漏れ等)を疑います
指標を特定せずに「なんとなく速くなりそうな施策」を積み重ねると、工数だけがかかって体感速度が変わらない、という結果になりがちです。まずは自社サイトの計測値を確認するところから始めてみてください。
パフォーマンス改善でよくある失敗パターンは?
「フレームワークをアップグレードすれば速くなる」という思い込みだけで着手し、アプリ側の実装は変えないまま効果を過大に期待してしまうのが典型的な失敗パターンです。
パフォーマンス改善に取り組む際、実際にあった失敗例を整理すると次のようになります。
| 失敗パターン | 何が起きたか | 回避のヒント |
|---|
| バージョンアップだけで満足 | 開発体験は改善したが、ユーザー向けの表示速度は変わらなかった | 開発体験の改善(ビルド・起動速度)とユーザー体感速度(Core Web Vitals)は別軸と理解する |
| 全画像にpriority指定 | ファーストビュー外の画像まで優先読み込みし、かえってLCPが悪化した | 実際に画面に映る最初の1〜2枚だけに絞る |
| 計測せずに手当たり次第に最適化 | 工数をかけたのに体感速度がほとんど変わらなかった | 着手前にCore Web Vitalsを計測し、ボトルネックを特定してから対策する |
| クライアントコンポーネントの過剰指定 | ページ全体が重いバンドルになり、初期表示が遅くなった | インタラクティブな要素だけを最小単位で切り出す |
こうした失敗の多くは、「何を」「なぜ」改善するのかを計測データで確認してから着手すれば防げるものです。
フレームワークのアップグレードで解決しない、もう1つの課題とは?
冒頭で触れた「もう1つの課題」を、ここで回収します。それは、継続的にバージョンアップを追従できる体制があるかどうかです。
Next.js 16系はこの記事で紹介した通り、16.0から16.3までの間に大きく進化しています。しかし、この恩恵を受けられるのは実際にアップグレードを実行したプロジェクトだけです。納品後に保守が止まっているシステムは、こうした改善を一切受け取れないまま、パフォーマンス面でも取り残されていきます。
私たちの実感では、パフォーマンス改善の相談を受けるプロジェクトの多くは、機能面の課題よりも先に「そもそも半年以上バージョンアップしていない」という状態に行き着きます。バージョンアップ運用を内製・外注どちらで進めるべきかの判断基準は内製か外注か、中小企業がNext.jsで選ぶ基準で整理しているので、あわせて確認してみてください。
ゼットリンカーでの進め方
私たちがNext.jsでパフォーマンス改善に取り組む際は、まず現状のCore Web Vitalsを計測し、ボトルネックを特定するところから始めます。フレームワークのバージョンアップと、画像・データフェッチ・バンドルサイズといった実装側の見直しをセットで進めることで、「アップグレードしたのに体感速度が変わらない」という事態を避けています。AI駆動開発を取り入れることで、こうした実装レベルの見直し作業(直列実行の検出、クライアントコンポーネントの過剰指定の洗い出し等)を効率的に進められる点も、私たちの強みです。
まずは自社サイトの主要ページで、ブラウザの開発者ツールやPageSpeed Insightsを使ってCore Web Vitalsを一度確認してみることをおすすめします。数値が既に良好であれば、この記事の内容は「今後崩れないための予防知識」として参考にしてください。
まとめ
この記事で持ち帰れることは、Next.jsのパフォーマンス改善を「フレームワークのバージョンアップ」と「アプリ側の実装(画像・データフェッチ・バンドルサイズ)」に切り分けて考える視点と、Core Web Vitalsを計測してから対策を選ぶという遠回りに見えて最短のアプローチです。
- Next.js 16.3時点でTurbopackは開発サーバーのメモリ使用量最大90%削減、リピートビルド最大5.5倍高速化を実現していますが、これらはバージョンアップだけで得られる恩恵です
- 画像最適化・データフェッチの並行化・クライアントJavaScriptの削減は、アプリ側の実装で差が出るため、フレームワークのアップグレードとは別に見直しが必要です
- Core Web Vitals(LCP・INP・CLS)のどれがボトルネックかを計測してから対策を選ぶことで、工数を無駄にしない改善ができます
パフォーマンス改善の相談は、既に数値が悪化している場合はもちろん、現状把握だけでも構いません。15分のカジュアル相談で、まずは計測から一緒に始めることも可能です。
本記事はNext.js 16.3時点の情報です。
技術仕様・対象バージョンは本文と参照先をご確認ください。
最終更新:2026年9月7日