言語を切り替える
テーマを切り替える

Next.js SSR vs SSG vs ISR:レンダリング戦略の選び方ガイド

「なぜトップページの読み込みに 3 秒もかかるんだ?」上司が Chrome DevTools のウォーターフォールを睨み、赤く伸びた TTFB のバーを指差しました。あのとき初めて、最初からレンダリング戦略を選び間違えていたのかもしれないと気づきました。

これは特別な話ではありません。Next.js の GitHub Issues でも、毎日のように「SSR と SSG、どっち?」「ISR を設定したのに効かない」という質問が上がります。ドキュメントは読んだはずなのに、具体的なプロジェクトではどれを選べばいいか迷う——以前の私もそうでした。

こんな悩み、ありませんか?

  • SSR にしたら初期表示が遅くてイライラする
  • SSG にしたら、ちょっとした更新でもサイト全体を再ビルドする
  • ISR は良さそうに見えるのに、設定しても全然動かない

この 3 つの戦略に「最強」はありません。あるのは「最適かどうか」だけです。本記事では、どの場面でどれを使うべきか、そしてよくある落とし穴の避け方を整理します。

40-60%
SSG の SSR 比高速化
AWS データ
50ms
SSG TTFB
Vercel 公式データ
200-500ms
SSR TTFB
Vercel 公式データ
2.3s→0.8s
ISR 性能向上
ある EC サイト実測
Source: AWS、Vercel 公式データおよび実践事例

まず押さえる:3 つのレンダリング戦略とは

選び方の前に、3 つの概念をできるだけ素直な言葉で整理しましょう。

SSG(静的サイト生成):作り置きのお弁当

お弁当屋を想像してください。朝に 100 個作ってカウンターに並べ、客が来たら渡すだけ。これが SSG です。

具体的には:

  • いつ生成するかnext build 実行時に、全ページの HTML を事前生成
  • ユーザーアクセス時:CDN が事前生成 HTML を返す。非常に速い
  • 向いている場面:内容があまり変わらないページ。企業サイト、製品紹介、ブログ記事など

メリット

  • 圧倒的に速い。AWS データでは SSG は SSR より 40〜60% 高速
  • TTFB(Time To First Byte)は通常 50ms 以内(Vercel 公式計測)
  • サーバー負荷はほぼゼロ。トラフィックが増えても安心
  • コストが低い。静的ファイルのホスティングは安価

制約もある

  • 内容を更新するには、サイト全体の再ビルドが必要
  • ページ数が増えるとビルド時間が長くなる。数千ページで 30 分超も
  • パーソナライズ不可。全ユーザーに同じ内容

要するに、SSG は「事前準備」で速度を買う戦略です。

SSR(サーバーサイドレンダリング):注文してから調理

今度は作り置きをやめます。客が注文したものを、その場で調理して渡す。これが SSR です。

具体的には:

  • いつ生成するか:ユーザーがリクエストするたびに、サーバーで HTML をリアルタイム生成
  • ユーザーアクセス時:DB 参照、API 呼び出し、HTML レンダリングを待ってから返却
  • 向いている場面:リアルタイム性やパーソナライズが必要なページ

メリット

  • 内容は常に最新。その瞬間のデータを表示できる
  • パーソナライズ可能。Cookie や権限に応じて内容を変えられる
  • リクエスト時にしか取れない情報(ヘッダー、クエリパラメータ)にアクセスできる

代償も大きい

  • 遅い。TTFB は通常 200〜500ms(Vercel 公式データ)
  • サーバー負荷が高く、トラフィック急増で耐えきれないことも
  • サーバーを常時稼働させる必要があり、コストも上がる

実例:ある EC サイトが SSR を採用し、初期表示に 2.3 秒かかっていた。ISR に切り替えて 0.8 秒まで短縮しました。

ISR(インクリメンタル静的再生成):作り置き + 定期更新

賢いやり方です。朝にお弁当を作り、1 時間ごとに入れ替える。客はほとんどの場合、作り置きを受け取るが、中身は古くなりすぎない。これが ISR です。

具体的には:

  • 初回ビルドnext build で静的 HTML を生成(SSG と同様)
  • その後の更新:設定した revalidate 時間に応じ、バックグラウンドでページを再生成
  • ユーザーアクセス時:多くの場合キャッシュ HTML を返す(速い)。期限切れならバックグラウンド更新

バランスの取れた選択

  • SSG の速度(静的ファイルを返す)
  • SSR の鮮度(定期的に更新される)
  • サイト全体の再ビルドは不要

設定はシンプル(App Router):

// app/posts/[id]/page.tsx
export const revalidate = 60; // 60 秒後に再検証

export default async function Post({ params }) {
  const post = await getPost(params.id);
  return <div>{post.content}</div>;
}

落とし穴もある

  • 設定しても効かない? 開発環境(next dev)でテストしている可能性。ISR は本番(next build + next start)でのみ動作
  • デプロイ先が非対応? Vercel はネイティブ対応。他プラットフォームは追加設定が必要な場合も

個人的には、ISR が今いちばんよく使う戦略です。SSG と SSR の弱点をうまく埋めてくれます。

判断フロー:どの場面で何を使うか

概念は押さえました。次は実務でいちばん大事な問い——自分のプロジェクトではどれを選ぶか。

焦らなくて大丈夫です。以下のフローに沿って、自分の要件と照らし合わせてみてください。

ステップ 1:3 つの質問に答える

質問 1:内容のパーソナライズは必要か?

ユーザーごとに異なる内容を出す必要があるなら、SSR が第一候補です。

典型例:

  • ユーザーダッシュボード(人によってデータが違う)
  • プロフィールページ
  • カートページ
  • 認証後にしか見られないページ

理由はシンプル。パーソナライズされた内容は事前生成できないからです。

質問 2:内容はどれくらいの頻度で更新されるか?

この答えが、SSG か ISR かを決めます。

  • 数秒〜数分で更新SSR

    • 株価、スポーツ速報、チャットメッセージなど
    • リアルタイム性が最優先なら SSR 一択
  • 数分〜数時間で更新ISR

    • ニュース、ブログトップ、商品一覧、EC 在庫など
    • revalidate: 300(5 分)などで、速さと鮮度を両立
  • ほとんど更新しない、または手動更新SSG

    • 企業サイト、製品紹介、ヘルプドキュメント
    • 数週間〜数ヶ月触らないコンテンツ向け

質問 3:トラフィック規模はどのくらいか?

規模はコストと性能の判断材料になります。

  • 超高トラフィック(日次 PV 100 万規模)SSG または ISR を優先

    • 静的ファイルを CDN で配信でき、コストと性能の両面で有利
    • SSR だとサーバー負荷とコストが急増しやすい
  • 中〜低トラフィック:3 つとも選択肢

    • リアルタイム性が必要なら SSR でも問題ないことも
    • ただ、ISR で足りるなら ISR の方が無難なことが多い

ステップ 2:シーン別クイックリファレンス

典型シーンを整理しました。自分のプロジェクトに当てはめてみてください。

SSG 向け

  • ✅ 企業コーポレートサイト
  • ✅ 製品紹介、料金ページ
  • ✅ マーケティング LP
  • ✅ ブログ記事詳細(公開後ほぼ修正しない)
  • ✅ 技術ドキュメント、API ドキュメント
  • ✅ ヘルプセンター、FAQ

キーワード:静的・公開向け・更新頻度が低い

SSR 向け

  • ✅ SNS タイムライン(Facebook、Twitter 型)
  • ✅ 個人ダッシュボード
  • ✅ カート、注文ページ
  • ✅ リアルタイムデータパネル
  • ✅ 検索結果(クエリパラメータ依存)
  • ✅ 認証が必要なページ(Cookie 判定)

キーワード:動的・パーソナライズ・リアルタイム

ISR 向け(個人的なおすすめ):

  • ✅ ブログトップ、記事一覧(定期的に新記事追加)
  • ✅ ニュースサイト
  • ✅ EC 商品詳細(価格・在庫が定期更新)
  • ✅ 掲示板スレッド(コメント数・いいね数に数分の遅延許容)
  • ✅ UGC プラットフォーム(秒単位のリアルタイム不要)
  • ✅ 天気予報、為替情報

キーワード:定期更新・遅延許容・高トラフィック

ステップ 3:混合利用が正解

よくある誤解:サイト全体を 1 つの戦略に統一する必要がある、というもの。

実際、多くのプロジェクトは混合構成です:

  • トップと商品一覧 → ISR(トラフィック大・定期更新)
  • 商品詳細 → SSG(内容安定)または ISR(価格・在庫変動)
  • ダッシュボード → SSR(パーソナライズ)
  • About、お問い合わせ → SSG(完全静的)

私たちの EC プロジェクトの例:

  • トップ(ISR、10 分更新)
  • 商品一覧(ISR、5 分更新)
  • 商品詳細(ISR、3 分更新。在庫変動のため)
  • カート(SSR、リアルタイム必須)
  • マイページ(SSR、パーソナライズ)
  • About、プライバシーポリシー(SSG、ほぼ不変)

この組み合わせで、性能とリアルタイム性のバランスが取れます。

一言で覚える判断の合言葉

まだ迷うなら、これを覚えてください。

静的なら SSG、リアルタイムなら SSR、定期更新なら ISR

それでも決めきれないときは、まず ISR を試すのが安全です。3 つの中で最もバランスが良く、失敗しにくい選択肢です。

3 大トラブルと解決策

理論は分かっても、現場では必ずハマります。私が踏んだ 3 つの落とし穴を共有します。

トラブル 1:ISR の revalidate が効かない

症状revalidate: 60 を設定したのに、1 分待っても内容が古いまま。

当時の私:初めて ISR を使ったとき、ここで 2 日間ハマりました。ドキュメントを読み漁り、設定を何度も変えても動かない。

原因は主に 3 つ

  1. 開発環境では ISR が動かない

    最も多い原因です。next dev では ISR は動作しません。本番モードでのみ有効です。

    対処

    # next dev では ISR をテストしない
    # 必ずビルドしてから起動
    npm run build
    npm run start
    
    # その後ページにアクセスして確認
  2. デプロイ先が ISR 非対応

    すべてのプラットフォームがネイティブ対応しているわけではありません。Vercel は Next.js 公式なので問題少なめ。Netlify などは @netlify/plugin-nextjs プラグインが必要な場合があります。

    確認方法:デプロイ先のドキュメントで「Next.js ISR support」を検索。

  3. CDN キャッシュが ISR を上書き

    Next.js の前段に Cloudflare などの CDN やリバースプロキシがあると、レスポンス全体がキャッシュされ、ISR の更新メカニズムが効かなくなることがあります。

    対処:CDN が Cache-Control ヘッダーを尊重するよう設定するか、ISR ページ向けに CDN キャッシュ時間を短くする。

おすすめ:ISR 設定後は必ず本番環境で検証。console.log(new Date()) でページ生成時刻を出力し、revalidate が効いているか確認しましょう。

トラブル 2:SSR の初期表示が遅すぎる

症状:SSR にしたら、初期表示の白画面が 2〜3 秒続く。

実例:あるプロジェクトで、トップを SSR にしてユーザー情報とおすすめコンテンツを取得。TTFB が 1.2 秒、レンダリング込みで 3 秒待たせる結果に。上司の反応は想像できます。

原因分析

SSR が遅いのは、多くの場合サーバー側のデータ取得がボトルネックです。

  • 外部 API のレイテンシが高い
  • DB クエリが遅い(インデックス不足、複雑な JOIN)
  • 直列リクエスト(1 つ終わるまで次を待つ)
  • サーバー性能不足、またはユーザーから地理的に遠い

解決策は 4 つ

  1. Streaming SSR と Suspense を使う(React 18+)

    全データを待ってから返すのではなく、ページの枠組みを先に返し、データ到着後にストリーミング配信します。

    // app/dashboard/page.tsx
    import { Suspense } from 'react';
    
    export default function Dashboard() {
      return (
        <div>
          <h1>ユーザーダッシュボード</h1>
          {/* 速く描画できる部分 */}
          <UserInfo />
    
          {/* 遅いデータは Suspense でラップ */}
          <Suspense fallback={<div>統計データを読み込み中...</div>}>
            <SlowStats />
          </Suspense>
        </div>
      );
    }

    ユーザーはより早く何かを見られるようになり、体感が大きく改善します。

  2. データ取得を並列化

    複数 API を直列で呼ばず、並列実行に切り替えます。

    // ❌ 直列:遅い
    const user = await getUser();
    const posts = await getPosts(user.id);
    
    // ✅ 並列:速い
    const [user, posts] = await Promise.all([
      getUser(),
      getPosts()
    ]);
  3. ISR への切り替えを検討

    SSR が必要だと思っていても、実は ISR で足りるケースは多いです。

    自問してみてください:本当にリアルタイムが必要か? 1 分程度の更新遅延が許容できるなら ISR で十分なことがあります。

    前述のトップページは ISR(revalidate: 60)に変更し、初期表示を 3 秒から 0.7 秒に短縮しました。

  4. Edge にデプロイ

    Vercel を使っているなら Edge Functions を試せます。SSR 関数をグローバル CDN ノードに配置し、ユーザーに近い場所で実行できます。

    // app/api/data/route.ts
    export const runtime = 'edge'; // この 1 行

トラブル 3:SSG のビルド時間が長すぎる

症状:数千ページあるサイトで next build が 20〜30 分かかり、タイムアウトで失敗する。

よくある場面:EC サイトに 5000 商品、ブログに 3000 記事。SSG だとビルド時に全ページの HTML を生成する必要があります。

なぜ遅いか

SSG はビルド時に全ページ HTML を生成します。ページが増えるほど時間がかかり、多くのページはそもそも誰もアクセスしない(ロングテール商品、古い記事)ことも。

解決策

  1. fallback 戦略を使う

    全ページを一度に生成せず、人気ページだけ事前生成し、他はオンデマンド生成します。

    // app/posts/[id]/page.tsx
    export async function generateStaticParams() {
      // 人気上位 100 記事だけ返す
      const posts = await getTopPosts(100);
      return posts.map(post => ({ id: post.id }));
    }
    
    // 他のページは初回アクセス時に生成
    export const dynamicParams = true;
  2. ISR と組み合わせる

    ビルド時はトップと人気ページのみ生成し、他は ISR でオンデマンド生成。

    ビルド時間を大幅に短縮でき、ユーザー体感速度も維持できます(キャッシュがあるため)。

  3. 増分ビルド(Incremental Builds)

    Vercel は増分ビルドに対応し、変更があったページだけ再ビルドします。1 記事更新のたびにサイト全体を再ビルドする必要はありません。

    他プラットフォームでは自前実装が必要な場合があります。

実際の効果

2000 記事のブログプロジェクトで、最初は純 SSG でビルドに 15 分かかっていました。変更後:

  • ビルド時は最新 50 記事のみ生成
  • 他は dynamicParams = true でオンデマンド生成
  • 全記事ページに ISR(revalidate: 3600)を適用

ビルド時間は 2 分に短縮。ユーザー体感速度は変わりませんでした。

Next.js 15 の新機能:React Server Components と PPR

ここまで来たら、Next.js 15 がもたらす 2 つの要素にも触れておきましょう。厳密には「レンダリング戦略」そのものではありませんが、ページの組み立て方に大きく影響します。

React Server Components(RSC):コンポーネント単位の SSR

Next.js 13+ の App Router を使っているなら、すでに Server Components を利用しています。

従来の SSR との違いは?

  • 従来の SSR:ページ全体をサーバーでレンダリング
  • RSC:デフォルトでコンポーネントをサーバーでレンダリング。インタラクションが必要な部分だけクライアントで実行

メリット

  1. JS バンドルが小さくなる

    Server Component のコードはクライアントに送られません。Next.js 公式データでは、RSC 導入後クライアント JavaScript ボリュームは 30〜50% 削減可能。

    ページ読み込みが速くなり、モバイル端末の負荷も下がります。

  2. バックエンドリソースに直接アクセス

    Server Component は DB クエリやファイルシステム読み取りができ、わざわざ API エンドポイントを作る必要がありません。

    // app/posts/page.tsx
    // Server Component。DB に直接アクセスできる
    async function getPosts() {
      const posts = await db.posts.findMany();
      return posts;
    }
    
    export default async function PostsPage() {
      const posts = await getPosts();
      return (
        <div>
          {posts.map(post => (
            <PostCard key={post.id} post={post} />
          ))}
        </div>
      );
    }

実践のアドバイス

  • デフォルトは Server Component(App Router のデフォルト)
  • インタラクションが必要な部分だけ Client Component('use client'
  • データ取得と静的 UI は Server Component、ボタン・フォーム・アニメーションは Client Component

SEO のメリットを保ちつつ、JS バンドルを小さく保てます。

Partial Prerendering(PPR):静的 + 動的のハイブリッド

PPR は Next.js 15 で導入された実験的機能で、同一ページ内で静的パートと動的パートを混在させられます。

例:EC 商品ページ

  • 商品説明、画像 → 静的(ビルド時生成)
  • 在庫、価格 → 動的(リクエスト時取得)

PPR なら、静的パートはビルド時に生成し、動的パートだけリクエスト時に計算。速さと鮮度を同時に狙えます。

使い方

// next.config.js
module.exports = {
  experimental: {
    ppr: true,
  },
};

// app/products/[id]/page.tsx
export const experimental_ppr = true;

export default function ProductPage({ params }) {
  return (
    <div>
      {/* 静的パート:ビルド時生成 */}
      <ProductDescription id={params.id} />

      {/* 動的パート:リクエスト時生成 */}
      <Suspense fallback={<div>読み込み中...</div>}>
        <DynamicStock id={params.id} />
      </Suspense>
    </div>
  );
}

大前提

PPR は現時点では実験的機能です。本番環境での全面採用はおすすめしません。非クリティカルなページで試す程度に留めましょう。

安定版(Next.js 16 あたり?)になれば、かなり強力な選択肢になるはずです。

新機能と SSR/SSG/ISR の組み合わせ

  • RSC + SSG:Server Component はデフォルト静的。SSG と相性抜群
  • RSC + ISR:Server Component + revalidate。静的でありつつ定期更新
  • RSC + SSR:動的ルートまたは dynamic = 'force-dynamic' で SSR 化
  • PPR:SSG と SSR の究極的な融合と言える

私の理解では、RSC は Next.js のアーキテクチャ刷新、SSG/SSR/ISR はその上のレンダリング戦略。対立ではなく、相補関係です。

まとめ

ここまで読んで、最初の問いに戻りましょう。SSR、SSG、ISR は結局どう選ぶか?

正解は 1 つではありません。プロジェクトごとに要件、トラフィック、予算が違います。ただ、次の 3 点が分かれば選択は難しくありません。

  1. パーソナライズは必要か? → 必要なら SSR
  2. 更新頻度は? → リアルタイムなら SSR、定期更新なら ISR、ほぼ不変なら SSG
  3. トラフィック規模は? → 超高トラフィックなら SSG または ISR を優先

記事冒頭の「なぜこんなに遅いのか」という場面、覚えていますか? あのトップページを SSR から ISR(revalidate: 60)に変更し、初期表示を 3 秒から 0.8 秒に短縮しました。上司も満足、ユーザー体験も改善。

私からのアドバイス

  • 迷ったらまず ISR を試す。3 つの中で最もバランスが良い
  • 公開後は Chrome DevTools の Performance パネルで TTFB、FCP などを実測
  • ページごとに戦略を変えてよい。教条に縛られない

レンダリング戦略は固定ではありません。プロジェクトが成長し、ユーザーが増え、要件が変われば、戦略も変えて問題ありません。Next.js では切り替えコストも比較的低いです。

本記事が、あなたのプロジェクトでいくつか落とし穴を避ける助けになれば幸いです。実践での経験やハマった話があれば、ぜひコメントで共有してください。

FAQ

SSR、SSG、ISR の核心的な違いは何ですか?
SSG はビルド時に全ページの HTML を生成し、ユーザーアクセス時は静的ファイルを直接返します。TTFB は通常 50ms 以内で高速ですが、更新には再ビルドが必要です。SSR はリクエストのたびに HTML をリアルタイム生成します。TTFB は通常 200〜500ms で内容は最新ですが、初期表示は遅くなりがちです。ISR は両者の長所を組み合わせ、ビルド時に静的 HTML を生成し、revalidate 時間に応じてバックグラウンドで自動更新します。
SSG、SSR、ISR はそれぞれいつ使うべきですか?
SSG:静的で公開向け・更新頻度が低いページ(企業サイト、製品紹介、ブログ記事詳細)。SSR:動的・パーソナライズ・リアルタイム向け(ユーザーダッシュボード、カート、リアルタイムデータパネル)。ISR:定期更新で多少の遅延が許容でき、トラフィックの多いページ(ブログトップ、ニュース、EC 商品詳細)。判断の合言葉:静的なら SSG、リアルタイムなら SSR、定期更新なら ISR。迷ったら ISR から試す。
ISR の revalidate を設定したのに効かないのはなぜですか?
主な原因は 3 つ。1) 開発環境(next dev)でテストしている。ISR は本番環境(next build + next start)でのみ動作するため、ビルド後に検証が必要。2) デプロイ先が非対応。Vercel はネイティブ対応だが、Netlify などはプラグインが必要な場合がある。3) CDN キャッシュが ISR を上書きしている。CDN が Cache-Control ヘッダーを尊重するよう設定する。本番環境で console.log(new Date()) を使い、ページ生成時刻を確認するのがおすすめ。
SSR の初期表示が遅い場合はどうすればいいですか?
最適化の方法:1) Streaming SSR と Suspense で、ページの枠組みを先に返し、データ到着後にストリーミング配信。2) Promise.all でデータ取得を並列化し、直列 await を避ける。3) 1 分程度の更新遅延が許容できるなら ISR へ。ある事例では 3 秒が 0.7 秒に短縮。4) Edge Runtime で Edge にデプロイし、レイテンシを低減。ボトルネック(API 遅延、DB クエリ、直列リクエスト、サーバー性能)を分析することが重要。
SSG のビルド時間が長すぎる場合はどうすればいいですか?
解決策:1) fallback 戦略で人気ページだけ事前生成(generateStaticParams で人気コンテンツのみ返し、dynamicParams = true)。2) ISR と組み合わせ、ビルド時はトップと人気ページのみ生成し、他は ISR でオンデマンド生成。3) 増分ビルド(Vercel 対応、他プラットフォームは自前実装)。実例:2000 記事を純 SSG(15 分)から fallback + ISR(2 分)に変更し、ユーザー体感速度は維持。
異なるレンダリング戦略を混在させられますか?
可能ですし、ベストプラクティスです。ページごとに戦略を変えられます:トップと商品一覧は ISR(トラフィック大・定期更新)、商品詳細は SSG(内容安定)または ISR(価格・在庫変動)、ダッシュボードは SSR(パーソナライズ)、About は SSG(完全静的)。EC サイトの例:トップ ISR(10 分)、一覧 ISR(5 分)、詳細 ISR(3 分)、カート SSR(リアルタイム必須)、マイページ SSR(パーソナライズ)、About SSG(ほぼ不変)。
React Server Components と SSR/SSG/ISR の関係は?
RSC は Next.js のアーキテクチャ刷新で、SSG/SSR/ISR はその上のレンダリング戦略です。相補関係にあります。RSC はデフォルトでサーバー側レンダリングされ、クライアント JavaScript ボリュームは 30〜50% 削減可能。組み合わせ:RSC + SSG(Server Component はデフォルト静的)、RSC + ISR(Server Component + revalidate)、RSC + SSR(動的ルートまたは dynamic = 'force-dynamic')。実践では Server Component をデフォルトにし、インタラクションが必要な部分だけ Client Component('use client')を使う。

7分で読めます · 公開日: 2025年12月19日 · 更新日: 2026年6月8日

関連記事

コメント

GitHubアカウントでログインしてコメントできます