Next.jsのgenerateStaticParamsで動的ルートを高速化!SSGとSSRのパフォーマンス比較
以前、Next.jsの基本について解説しましたが、今回はさらに一歩進んで、generateStaticParams
という関数に焦点を当ててみたいと思います。
generateStaticParams
とは、Next.jsで 動的なルート(Dynamic Routes) を持つページをビルド時に事前に生成(静的生成 - Static Generation)するための関数です。
例えば、products/[id]
のような動的なURLを持つページは、通常、ユーザーがアクセスするたびに[id]
をもとにデータを取得し、サーバーでページを生成(SSR)します。
しかし、generateStaticParams
を使えば、事前に特定のIDのページをビルド時に生成(SSG)しておくことができます。これにより、まるで静的なページのように、ユーザーを待たせることなく瞬時にページを表示させることが可能になります。
この記事では、generateStaticParams
を使う場合(SSG)と使わない場合(SSR)のサンプルコードを比較し、パフォーマンスにどのような違いが生まれるのかを分かりやすく解説していきます。
結論
まず結論からお伝えします。
generateStaticParams を使うべき時 (SSG)
- ブログ記事、製品詳細ページ、ドキュメントなど、内容の更新が頻繁ではないページ
- ユーザーごとに内容が変わらないページ
- とにかく速く、安く、安定してページを表示したい場合
generateStaticParams を使わないべき時 (SSR)
- ユーザーのダッシュボード、ショッピングカート、SNSのフィードなど、リクエストのたびに内容が変わる、またはパーソナライズされるページ
- 常に最新のデータを表示することが絶対条件の場合
generateStaticParams
を使わない場合(SSR)
generateStaticParams
を使わない場合、このページは動的レンダリングの対象となり、デフォルトではSSRとして扱われます。これはビルド時点には[id]
にどのような値が入るかわからないためランタイムで都度レンダリングする必要があるからです。
-
動き:ユーザーが
/products/1
や/products/2
にアクセスするたびに、サーバーがリクエストを受け取り、その都度HTMLを生成してブラウザに返します - 利点:常に最新のデータを表示できます
- 欠点:リクエストごとにサーバー処理が走るため、TTFB(Time to First Byte)が長くなり、ページの表示が遅れがちです
// データを取得する関数(例)
async function getProduct(id: string) {
const res = await fetch(`https://api.example.com/products/${id}`);
if (!res.ok) return undefined;
return res.json();
}
// ページコンポーネント
export default async function ProductPage({ params }: { params: { id: string } }) {
const product = await getProduct(params.id);
if (!product) {
return <div>商品が見つかりません</div>;
}
return (
<div>
<h1>{product.name}</h1>
<p>{product.description}</p>
</div>
);
}
このコードでは、ユーザーがアクセスしたURLの id を使って都度APIからデータを取得し、ページを生成しています。
generateStaticParams
を使う場合(SSG)
次に、generateStaticParams
を使って、事前にページを生成しておくパターンです。使わないパターンと違い[id]
にどのような値が入るかビルド時に確定しているためランタイムでレンダリングをする必要がありません。
-
動き:
next build
を実行するタイミングでgenerateStaticParams
が実行されます。この関数が返したid
のリストに基づいて、/products/1
,/products/2
... といったページが事前にHTMLファイルとして生成されます - 利点:ビルド時にページが生成済みなので、CDNから瞬時に配信できます。これにより、TTFBが劇的に短縮され、表示速度が非常に速くなります
-
欠点:ビルド時に存在しなかったデータ(新しい商品など)のページは、デフォルトでは表示できません。(
dynamicParams
オプションで挙動を変更可能)
import { notFound } from 'next/navigation';
// generateStaticParams: ビルド時に静的生成するパスのリストを返す
export async function generateStaticParams() {
const res = await fetch('https://api.example.com/products');
const products = await res.json();
// 'id' を文字列として含むオブジェクトの配列を返す
return products.map((product: { id: number }) => ({
id: String(product.id),
}));
}
// データを取得する関数(generateStaticParamsで使ったものと同じでOK)
async function getProduct(id: string) {
const res = await fetch(`https://api.example.com/products/${id}`);
if (!res.ok) return undefined;
return res.json();
}
// ページコンポーネント(SSRの場合とほぼ同じ)
export default async function ProductPage({ params }: { params: { id:string } }) {
const product = await getProduct(params.id);
if (!product) {
// generateStaticParamsで生成されなかったパスへのアクセスは
// notFound() を呼び出すのが一般的
notFound();
}
return (
<div>
<h1>{product.name}</h1>
<p>{product.description}</p>
</div>
);
}
NOTE
generateStaticParams
は、{ id: '1' }
,{ id: '2' }
のような、動的セグメント名(この場合はid
)をキーとし、その値を文字列で持つオブジェクトの配列を返す必要があります。
パフォーマンス比較:SSG vs SSR
では、両者のパフォーマンスには具体的にどのような違いがあるのでしょうか?
項目 |
generateStaticParams あり (SSG) |
generateStaticParams なし (SSR) |
---|---|---|
TTFB | 非常に速い | 遅い |
サーバー負荷 | 低い(CDNが処理) | 高い(リクエスト毎に処理) |
ビルド時間 | 長くなる(ページ数に比例) | 短い |
データの鮮度 | ビルド時のデータ | 常に最新 |
SSG (generateStaticParams) は、ブログ記事、マニュアル、ECサイトの商品詳細ページなど、内容の更新頻度がそれほど高くないページに最適です。ユーザーは爆速で表示されるページに満足し、サーバーコストも抑えられます。
一方、SSRは、ユーザーのプロフィールページ、管理画面のダッシュボードなど、リクエストごとに内容が変わるパーソナライズされたページに適しています。
まとめ
今回は、generateStaticParams
を使って動的なルートを静的生成(SSG)する方法について解説しました。
generateStaticParams
はビルド時に実行され、事前に生成するページのパス(パラメータ)をNext.jsに教える。- SSG化することで、ページの表示速度を大幅に向上させ、サーバー負荷を軽減できる。
- ページの特性(更新頻度など)に応じて、SSRとSSGを使い分けることが重要。
Next.jsのレンダリング戦略を理解すると、より快適でスケーラブルなアプリケーションを構築できます。