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

「なぜトップページの読み込みに3秒もかかるんだ?」上司が画面を睨みつけ、私は Chrome DevTools のウォーターフォールチャート——TTFB(Time To First Byte)の赤いバーが蛇のように伸びている——を凝視していました。その時初めて、最初のレンダリング戦略選びで失敗していたことに気づきました。
これは珍しいケースではありません。Next.js の GitHub Issues やコミュニティでは、毎日誰かが尋ねています。「SSR と SSG どっちがいい?」「ISR 設定したのに効かないんだけど?」正直、私も最初はドキュメントを読んでも、実際のプロジェクトでどれを選ぶべきか自信がありませんでした。
あなたも似たような悩みを持っていませんか?
- SSR を選んだら、TTFB が遅すぎてユーザーが離脱する
- SSG を選んだら、ちょっとした修正でサイト全体の再ビルドが必要になった
- ISR は理想的に見えるけど、設定してもキャッシュが更新されない
実は、これらの戦略に「最強」はありません。「最適」があるだけです。今日は、どのシナリオでどの戦略を使うべきか、そしてよくある落とし穴を回避する方法を徹底解説します。
まず理解しよう:3つのレンダリング戦略の違い
選び方の前に、概念を「お弁当屋さん」に例えて直感的に理解しましょう。
SSG(Static Site Generation):作り置き弁当
あなたは弁当屋を開きました。毎日朝一番に100個の弁当を作ってカウンターに並べます。客が来たら、すでにできている弁当を渡すだけ。これが SSG です。
具体的には:
- いつ生成するか:
next build実行時。全ページの HTML を事前に作ります。 - ユーザー訪問時:CDN が事前生成された HTML を即座に返します。超高速です。
- 向いている場面:内容が変わらないページ。企業サイト、製品紹介、ブログ記事など。
メリット:
- 爆速。SSR より圧倒的に速い。TTFB はほぼゼロ。
- サーバー負荷ほぼゼロ。CDN が全部やってくれます。
- 安い。静的ホスティングはコストが低い。
デメリット:
- 更新が大変。一箇所直すだけでサイト全体の再ビルドが必要。
- ビルド時間が長い。数千ページあると数十分かかることも。
- パーソナライズ不可。全員に同じ内容しか見せられない。
「事前準備」で速度を買う戦略です。
SSR(Server-Side Rendering):オーダーメイド弁当
今度は作り置きをやめました。客が来て注文してから、その場で調理して渡します。これが SSR です。
具体的には:
- いつ生成するか:ユーザーがリクエストするたびに、サーバーで HTML をリアルタイム生成。
- ユーザー訪問時:サーバーが DB を叩き、API を呼び、レンダリングして返すのを待ちます。
- 向いている場面:リアルタイム性やパーソナライズが必要なページ。
メリット:
- 常に最新。1秒前のデータ変更も反映される。
- パーソナライズ可能。ユーザーの権限や Cookie に応じて違う内容を出せる。
- リクエスト情報(ヘッダー、クエリパラメータ)にアクセスできる。
デメリット:
- 遅い。サーバー処理が終わるまでユーザーは待たされる。
- サーバー負荷が高い。アクセス集中でダウンするリスクがある。
- コストが高い。サーバーを常時稼働させる必要がある。
某 EC サイトの事例では、SSR を採用した結果、トップページの表示に 2.3秒 もかかっていました。
ISR(Incremental Static Regeneration):作り置き + 定期補充
今回は賢くなりました。朝に弁当を作っておきますが、1時間ごとに新しい弁当を作って入れ替えます。客は基本的に作り置きを受け取りますが、中身はそこそこ新しいです。これが ISR です。
具体的には:
- 初回ビルド:
next buildで静的 HTML を生成(SSGと同じ)。 - その後の更新:設定した
revalidate時間(例:60秒)が過ぎると、バックグラウンドでページを再生成してキャッシュを更新。 - ユーザー訪問時:ほぼ常にキャッシュされた 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)では効かない(常に SSR 扱いになる)。 - ホスティング環境依存。Vercel は完璧だが、他プラットフォームでは設定が必要な場合も。
正直、今の私はほとんどこれ(ISR)を使っています。SSG と SSR のいいとこ取りで、本当に快適です。
デシジョンツリー:どの場面で何を使う?
では、あなたのプロジェクトではどれを選ぶべきか? 以下のフローチャートで判断してください。
ステップ1:3つの質問に答える
Q1:内容はパーソナライズ(ユーザーごとに違う)が必要?
YES なら問答無用で SSR(またはクライアントサイドフェッチ)。
- ダッシュボード、マイページ、カート画面など。
- 事前生成できないからです。
Q2:内容はどれくらいの頻度で更新される?
- 秒単位〜分単位:SSR
- 株価、スポーツ実況、チャット。リアルタイム性が命。
- 分単位〜時間単位:ISR
- ニュースサイト、ブログトップ、商品一覧、在庫状況。
revalidate: 300(5分)などで十分対応可能。
- ほとんど更新しない:SSG
- 企業情報、ヘルプセンター、規約。
Q3:トラフィック(アクセス数)は?
- 超高トラフィック:SSG か ISR
- CDN で捌けるようにしないと、サーバー代で死にます。SSR は避けるべき。
- 中〜低トラフィック:どれでもOK。
- リアルタイム性が重要なら SSR でも耐えられます。
ステップ2:シーン別早見表
SSG 推奨:
- ✅ 企業コーポレートサイト
- ✅ LP(ランディングページ)
- ✅ ブログ記事詳細(公開後あまり修正しない)
- ✅ ドキュメント、マニュアル
SSR 推奨:
- ✅ SNS のフィード(Twitterライクなもの)
- ✅ ユーザー設定画面
- ✅ 注文履歴、決済画面
- ✅ 複雑な検索結果ページ
ISR 推奨(私のイチオシ):
- ✅ ブログトップ、記事一覧
- ✅ ニュースサイト
- ✅ EC の商品詳細(価格や在庫が変動する)
- ✅ 口コミ・レビューページ
- ✅ 天気予報
ステップ3:ハイブリッドが正解
「サイト全体で1つの戦略」にする必要はありません。Next.js の真骨頂は、ページごとに戦略を変えられることです。
私たちの EC プロジェクトの実例:
- トップページ:ISR(10分更新)。キャンペーンバナーなどが変わるため。
- 商品一覧:ISR(5分更新)。
- 商品詳細:ISR(1分更新)。在庫切れを反映するため短めに。
- カート・決済:SSR。絶対に最新で正確でないといけない。
- マイページ:SSR。ユーザー情報。
- 会社概要・規約:SSG。ほぼ不変。
これで、パフォーマンス(速度)とリアルタイム性のバランスが取れます。
一言で言うと?
迷ったら ISR。
静的なら SSG、リアルタイムなら SSR ですが、ISR はその中間で最も失敗が少ない安全策です。
3大トラブルと解決策
理論は分かっても、現場ではハマります。私が踏んだ地雷を共有します。
トラブル1:ISR の revalidate が効かない
症状:revalidate: 60 と書いたのに、何分待っても内容が更新されない。
原因と対策:
開発モード (
next dev) だった- ISR は
next build&&next start(本番モード)でしか動きません。開発中は常にリクエスト毎に再生成されます(デバッグしやすさのため)。 - 対策:必ずビルドして検証する。
- ISR は
CDN キャッシュの設定漏れ
- Cloudflare などを前段に置いている場合、CDN が古い HTML を長くキャッシュしてしまい、Next.js サーバーまでリクエストが届いていない可能性があります。
- 対策:CDN 側で
Cache-Controlヘッダーを尊重する設定にするか、パスごとのキャッシュルールを見直す。
トラブル2:SSR の首屏ロードが遅すぎる
症状:SSR にしたら画面が白くなる時間が2〜3秒続く。
原因:サーバー側でのデータ取得(API呼び出しなど)が遅い。直列で await している。
対策:
Streaming SSR と Suspense を使う
- 全部待たずに、殻(シェル)だけ先に返す。
export default function Page() { return ( <div> <Nav /> <Suspense fallback={<Skeleton />}> <SlowDataComponent /> </Suspense> </div> ) }これならユーザーは即座に何かを見ることができます。
並列リクエスト
awaitを連打せず、Promise.allで同時にデータを取る。
トラブル3:SSG のビルドが終わらない
症状:ページ数が5000を超えたあたりから、ビルド時間が30分を超え、タイムアウトでコケるように。
対策:
generateStaticParams (getStaticPaths) を絞る
- 全ページをビルド時に作ろうとしない。過去の記事やアクセスの少ない商品はビルド時には生成せず、初回アクセス時に生成(fallback)させる。
export async function generateStaticParams() { // 最新の100件だけ事前生成 const posts = await getLatestPosts(100); return posts.map(p => ({ slug: p.slug })); } // 他のページはアクセス時に生成(SSR的に振る舞い、その後キャッシュされる) export const dynamicParams = true;増分ビルド (Incremental Builds)
- Vercel などのプラットフォームなら、変更があったページだけを再ビルドしてくれます。
結論
SSR、SSG、ISR の選択に「正解」はありませんが、「定石」はあります。
- 基本は SSG/ISR で速度を確保する。
- パーソナライズが必要な部分だけ SSR(またはクライアントフェッチ)にする。
- 迷ったら ISR で様子を見る。
前述の「トップページが3秒かかる」案件は、結局 SSR から ISR (revalidate: 60) に変更し、0.8秒まで短縮しました。上司もニッコリです。
あなたのプロジェクトでも、まずは ISR を検討してみてください。もし実装で詰まったら、Twitter で聞いてください。
FAQ
SSR、SSG、ISR の最大の違いは何ですか?
ECサイトの商品ページはどれがいいですか?
ISR は Vercel 以外でも使えますか?
Next.js 15 の React Server Components はこれらとどう関係しますか?
5 min read · 公開日: 2025年12月19日 · 更新日: 2026年1月22日
関連記事
Next.js ファイルアップロード完全ガイド:S3/Qiniu Cloud 署名付き URL 直接アップロード実践

Next.js ファイルアップロード完全ガイド:S3/Qiniu Cloud 署名付き URL 直接アップロード実践
Next.js Eコマース実践:カートと Stripe 決済の完全実装ガイド

Next.js Eコマース実践:カートと Stripe 決済の完全実装ガイド
Next.js ユニットテスト実践:Jest + React Testing Library 完全設定ガイド


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