Next.js App Router で 空配列を返す generateStaticParams() と searchParams を同じページで併用すると、本番ビルド(build → start)時に 500 Internal Server Error が発生する。dev では再現しない。
app/[slug]/page.tsx:
export async function generateStaticParams() {
return []; // 空配列を返している
}
const Page = async (props: {
params: Promise<{ slug: string }>;
searchParams: Promise<{ [key: string]: string | string[] | undefined }>;
}) => {
const { slug } = await props.params;
const searchParams = await props.searchParams; // searchParams にアクセスしている
return (
<div>
<p>slug: /{slug}</p>
<p>searchParams: {JSON.stringify(searchParams)}</p>
</div>
);
};
export default Page;| 返り値 | ビルド時の動作 | リクエスト時の動作 |
|---|---|---|
generateStaticParams() がない |
パスを生成しない | 動的レンダリングされる |
[{ slug: "a" }, { slug: "b" }] を返す |
/a と /b が静的生成される |
生成済みのHTMLが返される |
[](空配列)を返す |
パスを生成しない | 初回アクセス時に静的生成され、以降はキャッシュされる |
空配列を返すパターンは、動的ルートのパスが多数存在し、ビルド時に全パスを生成するとビルド時間が長くなる場合に使用される。ビルド時のパス生成をスキップし、各パスへの初回アクセス時に生成・キャッシュする動作になる。
この3つ目のパターンが、今回の問題の前提となっている。ビルド時には静的としてマークされるが、実際のレンダリングはリクエスト時に行われる。
| 仕組み | 動作 | ページの扱い |
|---|---|---|
generateStaticParams() が空配列を返す |
ビルド時にはパスを生成せず、初回アクセス時にレンダリングする | 静的としてマークされる |
searchParams にアクセスする |
リクエスト時にしか値が確定しない | 動的として扱われる |
ビルド時に「静的」としてマークされたルートが、実行時に「動的」へ切り替わるため、500 エラーが発生する。
dev 環境ではこの静的/動的の区別が適用されないため、再現しない。
generateStaticParams() を削除すると、ルートは静的としてマークされなくなり、エラーは発生しない。変更箇所は generateStaticParams() の削除のみ。
const Page = async (props: {
params: Promise<{ slug: string }>;
searchParams: Promise<{ [key: string]: string | string[] | undefined }>;
}) => {
const { slug } = await props.params;
const searchParams = await props.searchParams;
return (
<div>
<p>slug: /{slug}</p>
<p>searchParams: {JSON.stringify(searchParams)}</p>
</div>
);
};
export default Page;空配列ではなく具体的なパスを返すと、ビルド時にルートが動的としてマークされるため、エラーは発生しない。ただし searchParams によりページは動的レンダリングされるため、generateStaticParams() で返したパスの静的生成は行われない。
export async function generateStaticParams() {
return [{ slug: "sample" }];
}force-dynamic を宣言すると、ルートはビルド時に動的としてマークされるため、エラーは発生しない。この場合、generateStaticParams() はビルド時の静的生成に使われず、動作に影響しない。
export const dynamic = "force-dynamic";
export async function generateStaticParams() {
return [];
}- 空配列を返す
generateStaticParams()とsearchParamsを併用すると、本番ビルドで 500 エラーが発生する devでは再現せず、build→startでのみ発生する- 原因は、ビルド時に静的としてマークされたルートが実行時に動的へ切り替わることにある