React

Next.jsのレンダリング方式|SSG・ISR・SSR・CSRの違いとApp Routerでの選び方

Next.jsのレンダリングは「SSG・ISR・SSR・CSRの4つから選ぶ」と説明されることが多いものの、App Routerではページ単位で方式を宣言する記述そのものが存在しません。決まるのは、コードがリクエスト時の情報に触れたかどうかと、どこにキャッシュ境界を置いたかです。2025年10月21日公開のNext.js 16でCache Componentsが入り、この前提はさらに変わりました。ここではApp Router(2026年7月時点の最新安定版は16.2.12)を基準に、各方式がどの記述に対応するのか、Cache Componentsで何が置き換わるのか、デプロイ先によってどの方式が使えなくなるのかを実装目線で整理します。レンダリング方式そのものの一般論はレンダリングとは?ブラウザ描画の仕組みとCSR/SSR/SSGの違い・選定基準を解説で扱っています。

まとめ|Next.jsのレンダリング選定で先に決める4点

App Routerで最初に決めるのは方式名ではなく、そのページがリクエスト時の情報(Cookie・ヘッダー・クエリ)を必要とするかです。必要なければ静的レンダリング、必要なら動的レンダリング、更新頻度だけが問題ならISRという順で絞れます。SSG・SSR・CSRという呼び分けは、Pages Router時代の関数名に対応した言い方が残ったものです。

Next.js 16でcacheComponents: trueを有効にすると既定が反転し、use cacheを書いた範囲だけがキャッシュされます。このとき部分プリレンダリング(PPR)が既定挙動になり、1ページの中に静的な部分と動的な部分が同居します。

残る2点は制約側です。デプロイ先が静的ホスティングならoutput: 'export'が必須で、その時点でISRもServer ActionsもCookieの読み取りも落ちます。そしてSEOでは、GooglebotがJavaScriptを実行する一方でGPTBotとClaudeBotは実行しないという差が、クライアント側だけで描画する構成の可否を分けます。以降の章で、この4点の根拠と実装を順に見ていきます。

App Routerのレンダリング判定|方式名より先に決まる静的と動的の分かれ目

App Routerのページは、ビルド時にレンダリングされる(静的レンダリング)のが既定です。この既定から外れる条件が明確に定義されており、方式を宣言するのではなく、条件に触れたかどうかで結果が決まります。

ランタイムAPIに触れた時点で動的レンダリング|静的化を外す4つのAPI

Next.jsのドキュメントがランタイムAPIとして挙げるのはcookiesheaderssearchParamsparamsの4つです。paramsだけは例外があり、generateStaticParamsで少なくとも1件のサンプルを渡していれば静的化の対象に残ります。これらはユーザーがリクエストを送って初めて確定する値なので、参照した時点でそのコンポーネントはビルド時に完成できなくなります。

重要なのは、この判定がページ全体ではなくコンポーネント単位で効くことです。ヘッダーやナビゲーションが静的なまま、Cookieを読む一部だけをリクエスト時に回すことができます。そのための境界が<Suspense>で、Cache Components有効時にこの境界を置き忘れると「Uncached data was accessed outside of <Suspense>」というエラーが開発時とビルド時に出ます。曖昧なまま全ページ動的に倒れる事故を、フレームワークがエラーで止める設計です。

Pages Routerの関数名との対応関係|getStaticProps・getServerSidePropsの移行先

Web上のNext.jsレンダリング解説の多くはPages Router前提で、getStaticPropsがSSG、getServerSidePropsがSSR、getStaticPathsrevalidateがISRという対応で説明されています。App Routerにこれらの関数はありません。Server Componentで直接データを取得し、静的化の可否をランタイムAPIの使用有無で表す形に置き換わっています。

方式 Pages Routerの記述 App Routerでの表現
SSG getStaticProps / getStaticPaths ランタイムAPI不使用 + generateStaticParams
ISR getStaticProps + revalidate export const revalidate
SSR getServerSideProps cookies() / headers() の参照
CSR useEffect / SWR 'use client' + SWR

Pages Router自体はNext.js 16でも動作しますが、新規実装のドキュメントはApp Router前提で書かれています。移行途中のプロジェクトで両者の記事を読み混ぜると、存在しないAPIを探すことになります。バージョンごとの変更点はNext.js 16とは?ReactベースのWeb開発フレームワーク最新版の概要や主要機能を詳しく紹介にまとめています。

SSG・ISR・SSR・CSRをNext.jsのAPIに対応づける|どの記述でどの方式になるか

ここからは、4方式がApp Routerのどの記述に落ちるかをコードで確認します。従来のキャッシュモデル(cacheComponentsを有効にしていない状態)が前提です。

SSG:generateStaticParamsによるビルド時HTML生成とページ数の上限

動的ルートを静的に出力するには、対象のパラメータ一覧をgenerateStaticParamsで返します。ここで返した分だけnext build時にHTMLが生成され、返していないパスへのアクセスはdynamicParamsの設定次第でオンデマンド生成か404に分かれます。ビルド時間はページ数に比例して伸びるため、数万ページ規模ではISRとの併用が現実解になります。

ISR:revalidateの秒数指定とタグ・パス単位の即時更新

ISRはページ単位のrevalidateエクスポートで有効になります。公式ドキュメントの最小例は次のとおりです。

// app/blog/[id]/page.tsx
export const revalidate = 60

export async function generateStaticParams() {
  const posts = await fetch('https://api.vercel.app/blog').then((res) => res.json())
  return posts.map((post) => ({ id: String(post.id) }))
}

Pageコンポーネント本体は省略していますが、挙動は次のとおりです。60秒が経過した後の最初のリクエストには古いページがそのまま返り、裏側で再生成が走ります。新しいページが返るのは2回目のリクエストからで、「60秒ごとに必ず最新になる」わけではありません。即時反映が必要なら、Server ActionからrevalidatePathでルート単位、revalidateTagでタグ単位に無効化します。

公式ドキュメントが明記する制約のうち、最も踏みやすいのはrevalidateの値が競合するケースです。同一ルートに複数のfetchがあり秒数がばらついている場合、ISRの周期には最も短い値が採用されます。いずれかのfetchrevalidate: 0またはno-storeを持つと、そのルートは静的化されず動的レンダリングへ倒れます。前提としてISRはNode.jsランタイム限定で、静的エクスポートでは使えません。

SSR:リクエスト時レンダリングになる条件と部分適用

App RouterでSSRを「選ぶ」記述はありません。cookies()headers()を参照した結果としてリクエスト時レンダリングになります。ログイン状態で出し分ける画面、在庫や価格をその場で読む画面が該当します。全画面をリクエスト時レンダリングにするとCDNキャッシュが効かなくなるため、出し分けが必要な範囲だけを切り出すのが基本形です。

CSR:Client ComponentとSWRでの取得と、初期HTMLが空になる代償

管理画面やダッシュボードのように検索エンジンに拾わせる必要がない画面は、'use client'を付けたClient ComponentからuseSWRなどで取得する構成で十分です。公式の静的エクスポート向けガイドでもこの組み合わせが例示されています。代償は初期HTMLに本文が入らないことで、後述のとおりGPTBotやClaudeBotはその本文に到達できません。概念面の比較はCSRとSSRの違いと使い分け|レンダリング方式を比較して実装で選ぶで詳しく扱っています。

Next.js 16のCache Components|ページ単位の方式選択が終わった理由

ここまでの整理は、Next.js 16で導入されたCache Componentsを有効にすると前提から変わります。公式ブログの表現では、従来のApp Routerにあった暗黙のキャッシュに対して、Cache Componentsのキャッシュは「entirely opt-in」(完全にオプトイン)です。

cacheComponents: trueによる既定の反転|use cacheを書いた範囲だけのキャッシュ化

有効化はnext.config.tscacheComponents: trueを追加するだけです。この状態では、ページ・レイアウト・APIルートの動的なコードはすべてリクエスト時に実行され、use cacheディレクティブを書いた関数やコンポーネントだけがキャッシュされます。有効期限はcacheLife('hours')のようなプロファイル、無効化の目印はcacheTag('posts')で指定します。引数や親スコープから閉じ込めた値が自動的にキャッシュキーになるため、ユーザーIDを引数に渡せばユーザーごとのキャッシュも作れます。

// app/blog-posts.tsx
import { cacheLife, cacheTag } from 'next/cache'

export async function BlogPosts() {
  'use cache'
  cacheLife('hours')
  cacheTag('posts')
  const res = await fetch('https://api.vercel.app/blog')
  const posts = await res.json()
  return <ul>{posts.slice(0, 5).map((p) => <li key={p.id}>{p.title}</li>)}</ul>
}

なお既定のuse cacheはインメモリ保存です。サーバーレス環境ではリクエストをまたいでメモリが残らないため毎回再評価されうると公式ドキュメントが注記しており、共有・永続化が必要なら'use cache: remote'を使います。

PPRが既定挙動|静的シェルとストリーミングの混在

Cache Componentsを有効にすると、部分プリレンダリング(PPR)が既定の挙動になります。ビルド時に静的シェル(HTMLとRSCペイロード)を作り、<Suspense>のフォールバックもそこに含め、リクエスト時のデータだけを後からストリーミングする形です。1ページの中で「ナビゲーションは静的、カートは動的」が同時に成立するため、ページ単位でSSGかSSRかを決める必要がなくなります。

PPRは2023年に発表されてから長く実験的な位置づけでしたが、Next.js 16ではexperimental.pprフラグとルート単位のexperimental_pprエクスポートが削除され、Cache Componentsの一部として提供される形に変わりました。experimental.dynamicIOcacheComponentsへ改称されています。古い記事のフラグ名をそのまま書くとビルドが通りません。

revalidateTagの引数追加とupdateTag・refreshの使い分け

Next.js 16ではrevalidateTag()でstale-while-revalidateの挙動を得るために第2引数のcacheLifeプロファイル指定が必要になり、単一引数の形は非推奨(将来のバージョンで削除予定)になりました。revalidateTag('blog-posts', 'max')のように書くと、古い値を即座に返しつつ背後で再生成します。

一方、投稿フォームのように「自分が書いた変更がその場で見えてほしい」場面ではServer Actions専用のupdateTag()を使います。こちらは同一リクエスト内で期限切れにして読み直すため、read-your-writesの一貫性が得られます。キャッシュに触れず未キャッシュのデータだけを更新したい場合はrefresh()です。この3つを取り違えると、更新されないバグか、キャッシュが効かない性能劣化のどちらかを踏みます。なお16.3系は2026年7月時点でプレビュー配布(16.3.0-preview.9)の段階で、安定版は16.2系です。先行して入る機能はNext.js 16.3とは?Turbopack永続キャッシュとInstant Navigationsなど新機能を実装者目線で解説で扱っています。

レンダリング方式とSEO|Googlebotは実行し、GPTBotとClaudeBotは実行しない

「SPAはSEOに弱い」という説明は、2026年時点では半分しか当たっていません。Googlebotは長くJavaScriptを実行してインデックスしており、CSRでも時間差はあれ拾われます。判断を分けるのは、Google以外のクローラーです。

ダイナミックレンダリングはGoogleが回避策と明記|新規採用しない判断

クローラーにだけ静的HTMLを返すダイナミックレンダリングは、Google検索セントラルが「a workaround and not a long-term solution」(回避策であり長期的な解決策ではない)と明記しています。追加の複雑さとリソースを要することが理由で、代わりにサーバーサイドレンダリング・静的レンダリング・ハイドレーションが推奨されています。既存実装を今すぐ壊す必要はないものの、新規案件でこれを設計に入れる理由はありません。App Routerであれば、必要な部分だけをサーバー側で描く形が標準で取れます。

AIクローラーのJavaScript未実行が意味すること|計測データから

Vercelが2024年12月17日に公開した自社ネットワークの計測(直近1か月でGPTBotが5億6,900万件、Claudeが3億7,000万件のリクエスト)では、GPTBotとClaudeBotはJavaScriptファイルを取得はするが実行しないと報告されています。各ボット自身のリクエストに占めるJavaScriptファイル取得の割合はChatGPT系が11.50%、Claude系が23.84%で、それでもクライアント側で描画されたコンテンツは読めません。同じ調査では、ブラウザベースで描画するのはAppleBotであり、GeminiはGooglebotの基盤を使うため完全に描画できるとされています。

つまり、クライアント側でしか本文が出ない構成は、生成AIの回答や引用元から構造的に外れます。検索流入だけでなくAI経由の到達も見込むなら、本文の初期HTMLはサーバー側で出すのが最低条件です。同調査ではChatGPT系の取得の34.82%、Claude系の34.16%が404へのアクセスだったとも報告されており、リンク切れの放置がクロール予算を空振りさせている実態も併せて示されています。なお計測は2024年12月時点のもので、各社のクローラーが後から描画能力を持つ可能性はあります。設計を決める前に、対象ボットの最新の挙動を確認してください。

デプロイ先で使える方式が決まる|static exportの制約とNode.jsサーバー運用

レンダリング方式の選定は、実際にはホスティングの選定と一体です。置き場所を決めた時点で、使える方式は絞り込まれます。

output: ‘export’で落ちる機能|GitHub PagesやS3へ置く前の確認

静的ホスティングへ置くにはnext.config.jsoutput: 'export'を指定し、next buildが生成するoutディレクトリを配信します。この構成で使えなくなる機能は公式ドキュメントに列挙されており、主なものは次のとおりです。

  • ISR(Incremental Static Regeneration)
  • Server Actions/Draft Mode/Intercepting Routes
  • Cookiesの読み取り
  • Requestに依存するRoute Handler
  • next.config側のRewrites・Redirects・Headers、およびProxy(旧middleware)
  • 既定のloaderによる画像最適化(カスタムloaderで代替)
  • generateStaticParamsのない動的ルート、およびdynamicParams: true

Route Handlerは静的エクスポートではGETのみが対象で、ビルド時にレスポンスが固定ファイルとして書き出されます。コンテンツ更新のたびに全体を再ビルドして配信する運用に耐えられるかが分岐点です。画像最適化はCloudinaryなどのカスタムloaderで置き換えられますが、ビルド時に最適化を完結させたい場合の選択肢はnext-export-optimize-imagesとnext-image-export-optimizerの違い|Next.js 16対応と選び方で比較しています。なおnext exportコマンドはv14.0.0で削除済みで、現在はoutput設定のみです。

自己ホストのISRで見落とす点|複数インスタンスのキャッシュ挙動

ISRはNode.jsサーバーでもDockerコンテナでも動きますが、既定のファイルシステムキャッシュはインスタンス単位です。複数コンテナで運用している環境でオンデマンド再検証を呼ぶと、そのリクエストを受け取ったインスタンスのキャッシュしか無効化されず、ロードバランサ次第で古いページが返り続けます。共有するにはcacheHandler(v14.1.0で安定)を設定して外部ストアに寄せる必要があります。

挙動の確認にはレスポンスヘッダーのx-nextjs-cacheが使えます。値はHIT(キャッシュ応答)、STALE(古い値を返しつつ背後で再生成)、MISS(未キャッシュ)、REVALIDATED(オンデマンド再生成後)の4種です。コンテナ構成そのものの最適化はDockerを使用したNext.jsアプリケーションの最適化手法を参照してください。

選定の判断基準|画面種別ごとの既定解と避けるべき組み合わせ

条件が揃っている場合の既定解は、次の対応で足ります。迷ったら静的側から始め、要件が満たせなくなった時点で1段ずつ動的側へ寄せるのが安全です。

画面 既定の選択 理由
LP・記事・製品情報 静的レンダリング 低更新・CDN配信可
一覧・カテゴリ ISR(時間単位) ビルド短縮+鮮度
在庫・価格を含む詳細 静的シェル + 動的部分 変動値のみ都度取得
マイページ・認証後 動的レンダリング Cookie参照で静的化不可
管理画面・社内ツール CSR 検索対象外・操作主体

避けたい選択のうち影響が最も大きいのは、検索流入を狙う公開ページをCSR単独で作ることです。Googlebotは拾えても、前章のとおりGPTBotとClaudeBotは本文に到達できません。次に効いてくるのが、鮮度を求めてrevalidateを1秒などに詰める設定です。公式ドキュメントは高めの値(1秒ではなく1時間)を推奨しており、精度が要るならオンデマンド再検証、リアルタイムが要るなら動的レンダリングへ切り替えるほうが筋が通ります。バックグラウンド再生成はリクエストを受けたインスタンスで走るため、リクエスト課金のプラットフォームでは短い周期がそのまま追加の計算コストとして計上される点も公式が注記しています。

Next.jsのレンダリング方式に関するよくある質問

ISRとは何ですか?

Incremental Static Regeneration(増分的静的再生成)の略で、サイト全体を再ビルドせずに静的ページを更新する仕組みです。App Routerではページにexport const revalidate = 60のように秒数を書くと有効になり、指定時間の経過後に来た最初のリクエストには古いページを返しつつ、裏側で新しいページを生成します。更新が見えるのは次のリクエストからです。Node.jsランタイムが前提で、静的エクスポートでは使えません。

プリレンダリング(prerender)はどの方式を指しますか?

Next.jsではビルド時またはリクエスト前にHTMLを用意しておくこと全般を指し、SSGとISRの両方が含まれます。CSRだけがプリレンダリングされない構成です。Next.js 16のCache Componentsでは、ページ全体ではなく静的シェルの部分だけを事前生成し、残りをストリーミングする部分プリレンダリング(PPR)が既定挙動になっています。

Next.jsはSPAとして使えますか?

使えます。ルート遷移はクライアント側で処理されるため、output: 'export'で静的書き出しをしても体験としてはSPAに近くなります。ただしその場合はISR・Server Actions・Cookie参照などが使えなくなるため、SPAらしい操作性が必要なだけであれば、静的レンダリングとClient Componentの組み合わせで十分なことがほとんどです。

SSGとSSRはどちらを選ぶべきですか?

リクエストごとに内容が変わるかどうかで決まります。全員に同じ内容を返せるならSSG、Cookieやヘッダーで出し分けるならSSRです。「同じ内容だが更新が頻繁」という中間はISRが担当します。判断に迷う場合は静的から始め、実際に静的化できない要件(認証・在庫・パーソナライズ)が出た箇所だけを動的に切り出すほうが、後戻りのコストが小さくなります。

Vercel以外にデプロイできますか?

できます。Node.jsが動くサーバーやDockerコンテナであればISRを含めほぼ全機能が使え、静的ホスティング(GitHub Pages・S3など)でもoutput: 'export'で配信できます。公式もGitHub Pages向けのテンプレートを公開しています。選定の実質的な違いは、ISR・Server Actions・画像最適化を使うかどうかです。

関連記事

資料請求

RELATED POSTS 関連記事