🧩
今更SSG / ISR / SSR / CSR の違いをまとめてみた
Next.js を使っていると必ず出てくる
- SSG
- ISR
- SSR
- CSR
の 4 つ。
「なんとなく理解したつもり…でも、
結局どう違うの?コード的にどう書くの?」
ここが一番つまずきやすいポイントです。
この記事では、
“本質レベルで理解できる説明” + “実際のコードでの書き分け”
を 1 つにまとめて、完全に腹落ちする形に整理します。
🎯 結論(これが分かれば全部理解できる)
Next.js の 4 方式の違いは、
👉 **React が動く前の“初期 HTML”を
どこで・いつ作るかの違いだけ。**
最終的にはどの方式でも React が動いて UI は動的になります。
違うのは 最初に返す HTML をどこで生成するか。
🍱 弁当の例えで 4 方式を完全理解する
| 方式 | HTML を作る場所 | いつ作る? |
|---|---|---|
| SSG | 店(サーバ/ビルド) | デプロイ前にまとめて作る |
| ISR | 店 | 作り置きしつつ、一定時間で作り直す |
| SSR | 店 | 注文が来てから毎回作る |
| CSR | 家(ブラウザ) | 食材だけ渡して、家で調理 |
React(調理道具)はどれでも最終的に動きます。
違うのは “どこでそれを使って初期 HTML を作るか” だけ。
🧩 各方式のポイント
■ SSG(Static Site Generation)
- デプロイ時に HTML を生成
- 初回表示が爆速
- 内容はしばらく固定
- SEO に強い
→ トップページ、ブログ、ヘルプページ に最適
■ ISR(Incremental Static Regeneration)
- SSG だけど “◯ 秒ごとに作り直す”
- 「速さ + 新鮮さ」の両立
→ ニュース一覧、商品一覧 に最適
■ SSR(Server Side Rendering)
- リクエストごとに HTML(初期 HTML)を生成
- 常に最新データ
- ユーザーごとに内容が違うページに強い
→ ダッシュボード・マイページに最適
■ CSR(Client Side Rendering)
- 初期 HTML は最低限
- 画面の構築は全部ブラウザ側で
- SEO は弱い
→ 設定画面、管理画面、フォーム多めの UI に向いてる
🎨 4 方式の比較表
| 方式 | HTML 生成のタイミング | 初回速度 | データ更新 | SEO |
|---|---|---|---|---|
| SSG | ビルド時 | 🌟 最速 | ❌ 固定 | 🌟 強い |
| ISR | ビルド時+再生成 | 🌟 速い | ◯ 更新される | 🌟 強い |
| SSR | リクエスト時 | △ 普通 | 🌟 最新 | 🌟 強い |
| CSR | クライアント | ❌ 遅め | 🌟 最新 | △ 弱い |
🔥 では、App Router ではどう書くべき?
ここからは App Router(app/ ディレクトリ)前提でのコード例 をまとめます。
Next.js 13+ の App Router では、
- 何も指定しないと 静的寄り(SSG 的)
-
revalidateで ISR -
dynamic = "force-dynamic"で SSR -
'use client'で CSR
と書き分けます。
① SSG(デフォルト)
app/posts/page.tsx
async function getPosts() {
const res = await fetch("https://example.com/api/posts");
return res.json();
}
export default async function PostsPage() {
const posts = await getPosts();
return (
<main>
<h1>Posts (SSG)</h1>
{posts.map((p: any) => (
<div key={p.id}>{p.title}</div>
))}
</main>
);
}
-
fetchのデフォルト = "force-cache" - 特に設定なし
→ SSG 的な(静的に生成される)ページ
② ISR(◯ 秒ごとに再生成)
app/news/page.tsx
export const revalidate = 60; // 60秒ごとに再生成
async function getNews() {
const res = await fetch("https://example.com/api/news");
return res.json();
}
export default async function NewsPage() {
const news = await getNews();
return (
<main>
<h1>News (ISR)</h1>
{news.map((n: any) => (
<div key={n.id}>{n.title}</div>
))}
</main>
);
}
③ SSR(毎回サーバで HTML を生成)
方法 A:ページ全体を「動的」にする
app/dashboard/page.tsx
export const dynamic = "force-dynamic";
async function getUser() {
const res = await fetch("https://example.com/api/me", {
cache: "no-store",
});
return res.json();
}
export default async function DashboardPage() {
const user = await getUser();
return (
<main>
<h1>Dashboard (SSR)</h1>
ようこそ {user.name} さん
</main>
);
}
方法 B:API Route を SSR 的にする
app/api/data/route.ts
export const dynamic = "force-dynamic";
export async function GET() {
const data = await fetch("https://example.com/api/live", {
cache: "no-store",
}).then(r => r.json());
return Response.json(data);
}
④ CSR(Client Side Rendering)
app/tools/page.tsx
"use client"; // CSR にする
import { useEffect, useState } from "react";
export default function ToolsPage() {
const [data, setData] = useState(null);
useEffect(() => {
fetch("/api/client-data")
.then(res => res.json())
.then(setData);
}, []);
if (!data) return <p>Loading...</p>;
return (
<main>
<h1>Tools (CSR)</h1>
<pre>{JSON.stringify(data, null, 2)}</pre>
</main>
);
}
🧩 書き分けチートシート
// SSG(デフォルト)
// → Server Component + デフォルトfetch
// ISR
export const revalidate = 60;
// SSR
export const dynamic = "force-dynamic";
// or fetch(..., { cache: "no-store" })
// CSR
("use client"); // + useEffect/useState など
🎯 まとめ
Next.js の SSG / ISR / SSR / CSR の違いは、
React が動く前の “初期 HTML” を
どこで・いつ生成するかの違いだけ。
そして App Router では、
- 何も指定しない:SSG 的
- revalidate:ISR
- dynamic="force-dynamic":SSR
- 'use client':CSR
とコードでハッキリ書き分けられます。
「このページは本当に SSR が必要?」
「ヘルプページは SSG + ISR で十分?」
「ログイン後 UI は CSR のほうが軽い?」
など、設計判断がとてもクリアになるはずです。
質問や「このページはどれを採用すべき?」などあれば、
気軽にコメントください 🙌🔥
Discussion