Dynamic segments use square brackets in folder names. A folder [slug] captures one URL segment; [...slug] catches the rest (catch-all); [[...slug]] makes the catch-all optional.
Examples
app/blog/[slug]/page.tsx → /blog/hello
app/shop/[...categories]/page.tsx → /shop/a/b/c
app/docs/[[...slug]]/page.tsx → /docs and /docs/guide/setup
Reading params
// app/blog/[slug]/page.tsx
type Props = { params: Promise<{ slug: string }> };
export default async function BlogPost({ params }: Props) {
const { slug } = await params;
return <h1>Post: {slug}</h1>;
}
In Next.js 15+, params and searchParams are async Promises—await them in Server Components.
generateStaticParams
Export generateStaticParams from a dynamic page to prebuild known slugs at build time—great for blogs and product catalogs.
Important interview questions and answers
- Q: Difference between [slug] and [...slug]?
A: Single segment vs one-or-more segments captured as an array. - Q: How do you type dynamic params?
A: Via the page props type; awaitparamsin async Server Components.
Self-check
- Which folder name handles
/products/42? - What does
generateStaticParamsenable?
Challenge
Param simulator
- Change the slug in the simulated
paramsobject. - Print a greeting that includes the slug.
- Run and confirm the terminal output updates.
Done when: terminal shows your custom slug in the greeting.
Pitfall: In Next.js 15+, params is a Promise—await it in async Server Components or TypeScript will lie to you at runtime.