Skip to content

Instantly share code, notes, and snippets.

@kobitoDevelopment
Created March 27, 2026 10:56
Show Gist options
  • Select an option

  • Save kobitoDevelopment/d884b450ebb077ead56643ee64b0ab83 to your computer and use it in GitHub Desktop.

Select an option

Save kobitoDevelopment/d884b450ebb077ead56643ee64b0ab83 to your computer and use it in GitHub Desktop.

Next.js: 空の generateStaticParams() + searchParams で 500 エラーになる問題

結論

Next.js App Router で 空配列を返す generateStaticParams()searchParams を同じページで併用すると、本番ビルド(buildstart)時に 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() の返り値による動作の違い

返り値 ビルド時の動作 リクエスト時の動作
generateStaticParams() がない パスを生成しない 動的レンダリングされる
[{ slug: "a" }, { slug: "b" }] を返す /a/b が静的生成される 生成済みのHTMLが返される
[](空配列)を返す パスを生成しない 初回アクセス時に静的生成され、以降はキャッシュされる

空配列を返すパターンは、動的ルートのパスが多数存在し、ビルド時に全パスを生成するとビルド時間が長くなる場合に使用される。ビルド時のパス生成をスキップし、各パスへの初回アクセス時に生成・キャッシュする動作になる。

この3つ目のパターンが、今回の問題の前提となっている。ビルド時には静的としてマークされるが、実際のレンダリングはリクエスト時に行われる。

なぜ起きるのか

仕組み 動作 ページの扱い
generateStaticParams() が空配列を返す ビルド時にはパスを生成せず、初回アクセス時にレンダリングする 静的としてマークされる
searchParams にアクセスする リクエスト時にしか値が確定しない 動的として扱われる

ビルド時に「静的」としてマークされたルートが、実行時に「動的」へ切り替わるため、500 エラーが発生する。

dev 環境ではこの静的/動的の区別が適用されないため、再現しない。


対処法

方法 1: generateStaticParams() を削除する

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;

方法 2: generateStaticParams() に具体的な slug を返す

空配列ではなく具体的なパスを返すと、ビルド時にルートが動的としてマークされるため、エラーは発生しない。ただし searchParams によりページは動的レンダリングされるため、generateStaticParams() で返したパスの静的生成は行われない。

export async function generateStaticParams() {
  return [{ slug: "sample" }];
}

方法 3: export const dynamic = "force-dynamic" を追加する

force-dynamic を宣言すると、ルートはビルド時に動的としてマークされるため、エラーは発生しない。この場合、generateStaticParams() はビルド時の静的生成に使われず、動作に影響しない。

export const dynamic = "force-dynamic";

export async function generateStaticParams() {
  return [];
}

まとめ

  • 空配列を返す generateStaticParams()searchParams を併用すると、本番ビルドで 500 エラーが発生する
  • dev では再現せず、buildstart でのみ発生する
  • 原因は、ビルド時に静的としてマークされたルートが実行時に動的へ切り替わることにある

参考

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment