Dynamic Routes and generateStaticParams in Next.js

A
Author
26 Jul, 2026 1 min read 1.32K views

Dynamic routes let one file serve many URLs, such as every blog post or product. With generateStaticParams you can pre-render the popular ones at build time.

Segment types

  • [slug] - one segment: /blog/hello.
  • [...slug] - catch-all: /docs/a/b/c gives ['a','b','c'].
  • [[...slug]] - optional catch-all: also matches /docs.

Pre-render at build time

// app/blog/[slug]/page.tsx
export async function generateStaticParams() {
  const posts = await getAllPosts();
  return posts.map((post) => ({ slug: post.slug }));
}

export default async function Post({ params }: { params: Promise<{ slug: string }> }) {
  const { slug } = await params;
  const post = await getPost(slug);
  if (!post) notFound();
  return <Article post={post} />;
}

Pages not returned by generateStaticParams

By default, other slugs are rendered on first request and then cached. To return a 404 for anything not pre-generated, export:

export const dynamicParams = false;

Large sites

Building 100,000 pages at deploy time is slow. Pre-render only the most visited pages and let the rest render on demand:

export async function generateStaticParams() {
  const top = await db.post.findMany({ orderBy: { views: 'desc' }, take: 500, select: { slug: true } });
  return top;
}

Nested dynamic segments

// app/shop/[category]/[product]/page.tsx
export async function generateStaticParams() {
  const products = await getProducts();
  return products.map((p) => ({ category: p.categorySlug, product: p.slug }));
}

Remember to call notFound() for unknown slugs so search engines get a real 404 instead of an empty page.

Was this article helpful?

Comments

No comments yet. Have a question or a tip? Be the first to share it.

Leave a comment

Comments are reviewed before they appear.