Three flavors of dynamic segment
| Folder pattern | Example URL | params shape |
|---|---|---|
[slug] | /blog/hello | { slug: 'hello' } |
[...slug] | /docs/a/b/c | { slug: ['a','b','c'] } |
[[...slug]] | /docs or /docs/a/b | { slug: undefined } or { slug: ['a','b'] } |
Multiple segments combine cleanly
You can have several dynamic segments in one path. params is the shape of all of them merged into a single object.
404 vs render
If a request hits /blog/foo and no generateStaticParams pre-built it, the default behavior is to render on demand. Set export const dynamicParams = false if you want unknown slugs to 404 instead.
Separate the set of routes worth prebuilding from the set of routes the product permits. generateStaticParams answers the first question. dynamicParams = false answers the second. Popular articles can be prebuilt while a long tail still renders on demand; a finite documentation version list may need strict 404s.
A catch-all route is not a shortcut for every hierarchy. When each segment has a distinct meaning, an array of strings hides the information architecture and weakens types. Use catch-all only when depth is genuinely open-ended, as with file paths or nested documentation. Request a single segment, several segments, and the empty optional catch-all. Compare a known prebuilt path with an unknown path before and after disabling dynamic params. Build output and HTTP status should both match the policy you wrote down.