generateStaticParams

Pre-render Dynamic Routes

generateStaticParams tells Next.js which values of a dynamic segment to build at build time. Other values can still be rendered on demand (and then cached), unless you set dynamicParams = false.

// app/products/[id]/page.tsx
import { prisma } from '@/lib/prisma';

export const revalidate = 3600;      // ISR for these pages
export const dynamicParams = true;   // ids not listed are rendered on first visit (default)

export async function generateStaticParams() {
  const top = await prisma.product.findMany({ orderBy: { sales: 'desc' }, take: 500, select: { id: true } });
  return top.map((p) => ({ id: String(p.id) })); // values must be strings
}

export default async function ProductPage({ params }: { params: Promise<{ id: string }> }) {
  const { id } = await params;
  // ...
  return <h1>Product {id}</h1>;
}

Example

npm run build

Example output

Route (app)                         Size  First Load JS  Revalidate  Expire
└ ● /products/[id]                 1.1 kB         104 kB          1h      1y
    ├ /products/1
    ├ /products/2
    ├ /products/3
    └ [+497 more paths]

Multiple Segments

Example

For app/[locale]/category/[slug]/page.tsx you return every combination. The logic in plain TypeScript:

type Params = { locale: string; slug: string };

const locales = ['en', 'hi'];
const categories = ['mobiles', 'books', 'fashion'];

function generateStaticParams(): Params[] {
  return locales.flatMap((locale) => categories.map((slug) => ({ locale, slug })));
}

const params = generateStaticParams();
console.log(params.length + ' pages');
for (const p of params) console.log('/' + p.locale + '/category/' + p.slug);

Output

6 pages
/en/category/mobiles
/en/category/books
/en/category/fashion
/hi/category/mobiles
/hi/category/books
/hi/category/fashion

Tips

  • Pre-render your most visited pages (top sellers), not all 2 million products: builds stay fast and the rest are rendered on first request.
  • Return an empty array plus dynamicParams = true to render everything on demand but still cache it statically.
  • Parent segments' params are passed to child generateStaticParams as an argument.