Lesson 24 of 81
A blog with 10,000 posts doesn't need all 10,000 pre-rendered at build time to get the benefit of static rendering. generateStaticParams picks which ones are worth the build-time cost, and dynamicParams decides what happens to everyone else.
12 min read
Every option explains itself — why the right one is right, and why each wrong one is wrong. Miss one and it comes back later on a spaced-repetition schedule.
Question 1 of 3
`generateStaticParams` returns the top 10 blog post slugs, and `dynamicParams` is left at its default. A visitor requests the 11th post, which wasn't in that list. What happens?
Hints without spoilers, and a plain explanation of why a wrong answer was wrong — answered only from this lesson. Free account, no card.
Sign up freeWhat interviewers actually ask about this, and what a strong answer has to cover.
A strong answer covers
Likely follow-ups
generateStaticParams is a function you export from a dynamic route's page.tsx (or layout.tsx, or route.ts) that returns the list of param values Next.js should pre-render at build time. It's the App Router's direct replacement for the Pages Router's getStaticPaths — same job, new name and shape.
You don't have to list every possible value. Return the ones worth building ahead of time (your top 10 blog posts, say), and dynamicParams — a route segment config option — decides what happens when someone requests a value that wasn't in that list:
dynamicParams = true (the default) — render it on demand, the first time it's requested.dynamicParams = false — return a 404 immediately, no on-demand rendering at all.// app/blog/[slug]/page.tsx
export const dynamicParams = false;
export async function generateStaticParams() {
const posts = await fetch("https://api.example.com/posts").then((r) => r.json());
const topPosts = posts.slice(0, 10);
return topPosts.map((post: { slug: string }) => ({ slug: post.slug }));
}
export default async function Page({ params }: { params: Promise<{ slug: string }> }) {
const { slug } = await params;
// ...
}
Only the ten slugs returned by generateStaticParams get built ahead of time. With dynamicParams left at its default of true, requesting the eleventh post still works — Next.js renders it the first time it's visited, exactly like a normal dynamic request. Setting it to false here, as above, changes that: any slug not in the top ten returns a 404 outright, with no fallback rendering. That's a real product decision, not just a performance knob — it's the difference between "these ten are pre-built and everything else still works" and "only these ten exist."
For nested dynamic segments — app/products/[category]/[product]/page.tsx — a child segment's generateStaticParams can generate values for every dynamic segment above it in the route, generating from the bottom up in one function:
// app/products/[category]/[product]/page.tsx — bottom-up
export async function generateStaticParams() {
const products = await fetch("https://api.example.com/products").then((r) => r.json());
return products.map((p: { category: string; id: string }) => ({
category: p.category,
product: p.id,
}));
}
Or you can generate params top-down: a parent layout.tsx generates [category] values, and the child page.tsx's own generateStaticParams receives each generated category as an argument and generates [product] values scoped to it — the child function runs once per parent-generated param set, not once overall.
dynamicParams doesn't control whether params are pre-rendered — generateStaticParams does that. dynamicParams only controls what happens to everything not in that list. They're two separate decisions that combine, not one setting.app/products/[category]/layout.tsx can generate [category] values; it cannot reach down and generate [product] values for its child page — only page.tsx (or a segment at that level) can generate a segment's own params.generateStaticParams isn't a no-op — it silently makes the route fully dynamic, the opposite of what adding the function usually signals you're trying to do.generateStaticParams replaces getStaticPaths, but the mental model shifted with it — there's no separate fallback: true | false | blocking enum anymore; dynamicParams: true | false does that job, mapped roughly to fallback: true and fallback: false respectively.next build, generateStaticParams runs before the Page/Layout it belongs to is generated — and during ISR revalidation, it does not run again. The list of statically known params is fixed at build time even if the underlying function could theoretically return something different later."You have a product catalog with 50,000 SKUs — how would you decide what to pre-render at build time, and what happens to a SKU you didn't pre-render?" tests whether a candidate understands generateStaticParams and dynamicParams as two separate, composable decisions, rather than treating "static generation" as one all-or-nothing switch.