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/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.
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/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
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.
Frequently Asked Questions
Can a route have more than one dynamic segment?
What type does a dynamic segment value have?
Do I have to use generateStaticParams?
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.
More in this topic
`generateMetadata` Explained with Real Examples
What generateMetadata does, when it runs, and how to use it for real routes: awaited params, deduplicated data fetching, extending parent metadata, and returning a 404 from metadata.
Canonical URLs in Next.js: `metadataBase`, `alternates.canonical`, and Dynamic Pages
How canonical URLs work in the Next.js App Router: setting metadataBase once, writing alternates.canonical per route, handling dynamic segments, and what happens when the base URL is missing.
Open Graph and Twitter Card Metadata in Next.js
How to write Open Graph and Twitter card metadata in the Next.js App Router: the openGraph and twitter fields, automatic card defaults, article tags, and image merge rules.