Dynamic Routes in Next.js: `[slug]` Segments Explained

A dynamic route lets one folder match many URLs. Learn how bracketed folder names capture values and how to prerender them ahead of time.

7 min read

Next.js dynamic routes let one folder in the App Router match many different URLs. Wrap a folder name in square brackets, like [slug], and Next.js treats that part of the path as a placeholder instead of a fixed value.

App.tsxApp.tsx
// app/blog/[slug]/page.tsx
export default async function Page({
  params,
}: {
  params: Promise<{ slug: string }>;
}) {
  const { slug } = await params;
  return <h1>Post: {slug}</h1>;
}

Visiting /blog/hello-world or /blog/next-js-16 both match this same file, and the value after /blog/ lands in the slug property. One folder now serves an unlimited number of blog post URLs.

How the folder name becomes a prop

The name inside the brackets becomes the key in the params object. Rename the folder from [slug] to [postId] and the page reads a different property on that object. The name is arbitrary, but it should describe what the segment holds.

texttext
app/blog/[slug]/page.tsx    -> /blog/hello-world -> { slug: "hello-world" }
app/shop/[category]/[item]/page.tsx -> /shop/shoes/nike -> { category: "shoes", item: "nike" }

Every dynamic segment in the path contributes one key. A route with two bracketed folders, like the shop example, produces an object with both values filled in.

Prerendering known values

By default, Next.js renders a page for a dynamic segment the first time a matching URL is requested. To prerender specific values ahead of time, export a generateStaticParams function that returns the list of values to build.

App.tsxApp.tsx
// app/blog/[slug]/page.tsx
export async function generateStaticParams() {
  const posts = await fetch("https://api.example.com/posts").then((res) =>
    res.json()
  );
  return posts.map((post: { slug: string }) => ({ slug: post.slug }));
}

Each object in the returned array becomes one prerendered page at build time. A slug the function did not return still works; Next.js renders it on the first request instead and can save the result for later requests, depending on the caching model in use.

When to use a dynamic segment

Reach for a dynamic segment whenever a set of pages shares the same layout and logic but differs by one identifying value, such as a blog post, a product, or a user profile. Building one templated page instead of hundreds of near-identical files keeps the route maintainable as the underlying data grows. If the page content does not depend on any part of the URL, a plain static route is simpler and needs no params handling at all.

A dynamic segment can also sit in the middle of a path, not just at the end. A route like app/[locale]/blog/[slug]/page.tsx captures both a language code and a post slug from the same URL, and each becomes its own key on the params object.

Common mistake

Treating the captured value as a number without converting it is a frequent mistake. A segment value is always a string, so comparing it to a number with strict equality, or passing it straight into a function expecting one, produces a bug that only shows up with certain inputs. Convert it explicitly before using it as anything other than text.

For matching more than one path segment inside a single folder, see catch-all and optional catch-all routes. To go deeper on generateStaticParams itself, see generateStaticParams explained with real examples.

Rune AI

Rune AI

Key Insights

  • Wrap a folder name in square brackets to create a dynamic segment.
  • The captured value arrives on the params prop, typed as a string.
  • A route can nest multiple dynamic segments, one per folder level.
  • generateStaticParams prerenders known values for the segment at build time.
  • Values not returned by generateStaticParams still render, just at request time.
RunePowered by Rune AI

Frequently Asked Questions

Can a route have more than one dynamic segment?

Yes. A path like app/shop/[category]/[item]/page.tsx has two dynamic segments, and params resolves to an object with both category and item keys.

What type does a dynamic segment value have?

A single bracketed segment always resolves to a string, because URL path segments are text. Next.js does not convert it to a number or boolean automatically.

Do I have to use generateStaticParams?

No. Without it, Next.js still serves every value for the segment; it just renders each one at request time instead of prerendering it at build time.

Conclusion

A dynamic segment lets a single folder serve many URLs by capturing part of the path into the params prop. Add generateStaticParams when you want known values prerendered ahead of a request instead of rendered on demand.