How dynamic routes work
Catch-all. Adding an ellipsis inside the brackets (
[...slug]) creates a catch-all segment that matches all deeper path segments and returns them as an array.Optional catch-all. Double square brackets (
[[...slug]]) make a catch-all optional, so the route also matches the path with no parameter, such as/shop.Pages Router. The bracket convention applies to a file or folder name, as in
pages/blog/[slug].js, and the value is read withuseRouter.
Client Components can read dynamic params anywhere in their tree with the useParams hook. Route params are typed as string, string[] or undefined because users can type any URL, so their values are only known at runtime. In Next.js 15, the page params and searchParams props became Promises, read with async/await or React's use function; before that they were plain objects, and a codemod helps migrate. Next.js vs React compares this folder-based routing with a plain React app.
Prerendering dynamic routes
generateStaticParams works with dynamic segments to prerender routes at build time instead of at request time. In the App Router, generateStaticParams replaces the Pages Router getStaticPaths function. The dynamicParams segment option defaults to true, which renders params missing from generateStaticParams at request time; setting it to false returns a 404 for them. dynamicParams is not available when Cache Components is enabled (Next.js 16). dynamicParams takes over the role of the getStaticPaths fallback option (true, false or 'blocking'). In the Pages Router, a dynamic-route page that exports getStaticPaths has every path it returns prerendered statically.
With Cache Components (Next.js 16). generateStaticParams for a dynamic route must return at least one param; an empty array fails the build. With no generateStaticParams, params count as runtime data, so reading them must be wrapped in a Suspense boundary. For rendering choices that slow pages down, see common Next.js mistakes that hurt Core Web Vitals.
A dynamic-route test Pagepro runs
Under ISR, a nested dynamic route such as /products/[group]/[id] can render on a direct load and show a blank screen when reached through client-side navigation, because the two take different code paths and cache keys. Pagepro tests every dynamic route twice, once by direct URL and once through internal navigation. For routing bugs on a live site, see Next.js support.
Sources
- Dynamic Route SegmentsNext.js · nextjs.org
- Dynamic Routes (Pages Router)Next.js · nextjs.org
- page.jsNext.js · nextjs.org
- generateStaticParams - API Reference (App Router)Next.js · nextjs.org
- dynamicParamsNext.js · nextjs.org
- getStaticPathsNext.js · nextjs.org