Dynamic routes use bracketed folder names to match variable URL segments, and generateStaticParams tells Next.js which of those pages to pre-render at build time (for SSG/ISR).
Dynamic segment
() {
post = (params.);
;
}
// Tell Next.js the list of slugs to build statically
export async function generateStaticParams() {
const posts = await getAllPosts();
return posts.map(post => ({ slug: post.slug }));
// → builds /blog/post-1, /blog/post-2, ... as static HTML at build time
}
Without this, a dynamic route is rendered on-demand (SSR). With it, Next.js pre-generates a static page for each returned param at build — giving you the speed of SSG for a known set of dynamic pages (every blog post, every product).
// what happens for a slug NOT returned by generateStaticParams?
export const dynamicParams = true; // (default) render unknown slugs on-demand (ISR-like)
// export const dynamicParams = false; // return 404 for any slug not pre-built
This lets you pre-build your top/most-common pages and still serve (or 404) the long tail.
app/shop/[...categories]/page.tsx → /shop/a/b/c (params.categories = ['a','b','c'])
app/[lang]/[slug]/page.tsx → multiple params: { lang, slug }
export async function generateStaticParams() {
return [{ lang: "en", slug: "about" }, { lang: "vi", slug: "about" }];
}
This pair is how you statically generate large sets of dynamic pages (blogs, e-commerce catalogs, docs) for top performance and SEO, while dynamicParams controls the fallback for pages not built ahead of time.
Understanding generateStaticParams (which pages to pre-build) plus the caching/revalidate options is the core of doing SSG/ISR for dynamic content in the App Router.