Back to Next.js tutorials
Intermediate13 min read

Dynamic Routes

Build routes with dynamic segments, catch-all paths, and static generation at scale.

Dynamic Segments

Bracket folders create dynamic params: `app/users/[id]/page.tsx` matches `/users/123` with `params.id === '123'`. Multiple dynamic segments stack: `[orgId]/projects/[projectId]`.

Access params in pages as props — in newer Next.js versions params is a Promise requiring await. Type params with TypeScript interfaces for compile-time safety.

  • [param] folders for dynamic segments
  • params prop on page components
  • Await params in async pages
export default async function Page({
  params,
}: { params: Promise<{ id: string }> }) {
  const { id } = await params;
  return <UserProfile id={id} />;
}

Catch-All and Optional Catch-All

`[...slug]` matches one or more segments: `/docs/a/b/c` → `{ slug: ['a','b','c'] }`. `[[...slug]]` optional catch-all also matches zero segments — `/docs` is valid.

Use catch-all for documentation sites, CMS-driven paths, and file-browser UIs. Validate slug arrays before fetching — reject malformed paths early with notFound().

  • [...slug] for one or more segments
  • [[...slug]] includes zero segments
  • Validate slug arrays before data fetch

generateStaticParams

Pre-render dynamic routes at build time by exporting `generateStaticParams` returning an array of param objects. Next.js generates static pages for each combination — essential for CMS content with known slugs at build time.

Combine with `dynamicParams = false` to 404 unknown slugs not in generateStaticParams. Use `true` (default) to on-demand render new slugs after build.

  • generateStaticParams for build-time paths
  • dynamicParams controls unknown slug behavior
  • Ideal for CMS with known content list
export async function generateStaticParams() {
  const posts = await getPosts();
  return posts.map(p => ({ slug: p.slug }));
}

Route Handlers with Params

Route Handlers in dynamic folders receive params similarly: `app/api/users/[id]/route.ts`. Export GET, POST, PUT, DELETE functions handling REST endpoints per resource ID.

Share param validation (Zod) between page components and route handlers to ensure consistent ID format enforcement across UI and API.

  • Dynamic route.ts for REST endpoints
  • Same param patterns as pages
  • Shared validation schemas

Search Params and Filtering

Pages receive `searchParams` for query strings — `/products?sort=price&category=shoes`. searchParams is also async in newer versions. Use for filters, pagination, and tab state that should be shareable via URL.

Validate and sanitize searchParams before using in queries — prevent injection and invalid enum values. Default missing params to sensible defaults.

  • searchParams for query string state
  • Shareable filter and pagination URLs
  • Validate params before queries

Get In Touch


Ready to discuss your next project? Drop me a message.