In modern web development, creating pages with flexible, data-driven content is essential. You can’t manually create thousands of pages for products, blog posts, or user profiles. This is where Dynamic Routes in Next.js shine, offering a powerful, flexible, and SEO-optimized solution.
This article will take you from the basics to advanced techniques, so you can fully master Dynamic Routes in your Next.js projects.
What are Dynamic Routes? Why are they important?
Imagine you’re building an e-commerce site. Instead of creating a separate file for each product (product-1.js
, product-2.js
, ...), you just create a single "template" page, and its content changes automatically based on the product’s ID or a URL-friendly "slug".
That’s the power of Dynamic Routes.
Dynamic Routes are routes (URLs) that aren’t hardcoded, but are generated flexibly based on data—such as product IDs, blog post titles, or usernames.
Key benefits:
- Component reuse: One page layout for countless subpages with similar structure.
- Easy management: No need to handle hundreds or thousands of separate files.
- SEO-friendly URLs: Create meaningful, readable URLs (e.g.,
/blog/how-to-use-nextjs
instead of/blog?id=123
), improving search rankings. - Flexible with data: Easily display content from any data source (API, database, markdown files, ...).
Syntax and How It Works in the App Router
With the App Router, defining Dynamic Routes is more intuitive than ever, based on folder structure.
1. Basic Dynamic Segments
To create a dynamic route, just name a folder in square brackets: [folderName]
. The name inside the brackets becomes a parameter for your route.
Example: Create a blog post detail page.
Your folder structure:
app/
└── blog/
└── [slug]/
└── page.js
- With this structure, any URL like
/blog/post-a
,/blog/what-is-nextjs
, or/blog/123
will be handled byapp/blog/[slug]/page.js
. - The values "post-a", "what-is-nextjs", or "123" are the
slug
parameter.
How to get the parameter value?
In page.js
(a default Server Component), Next.js automatically passes route parameters into the component’s props.
// app/blog/[slug]/page.js
// Example data fetch function
async function getPostData(slug) {
// Suppose you fetch data from an API
const res = await fetch(`https://api.example.com/posts/${slug}`)
if (!res.ok) return { title: 'Post not found', content: '' }
return res.json()
}
export default async function BlogPostPage({ params }) {
// params is an object: { slug: 'post-a' }
const { slug } = params
const post = await getPostData(slug)
return (
<div>
<h1>{post.title}</h1>
<p>
This is the content for the post with slug: <strong>{slug}</strong>
</p>
<div dangerouslySetInnerHTML={{ __html: post.content }} />
</div>
)
}
2. Catch-all Segments
Want a route to "catch" multiple URL segments? For example, a docs page with URLs like /docs/getting-started/installation
.
Use the spread syntax inside brackets: [...folderName]
.
Example:
Folder structure:
app/
└── docs/
└── [...slug]/
└── page.js
- This route matches
/docs/a
,/docs/a/b
,/docs/a/b/c
, and so on. - The
slug
parameter is now an array of segments.
How to get the value:
// app/docs/[...slug]/page.js
export default function DocsPage({ params }) {
// For /docs/getting-started/installation
// params: { slug: ['getting-started', 'installation'] }
const { slug } = params
return (
<div>
<h1>Docs for: {slug.join(' / ')}</h1>
{/* Render content based on the slug array */}
</div>
)
}
3. Optional Catch-all Segments
A variant of Catch-all is Optional Catch-all, which lets the route match the base URL (no parameter). Use double brackets: [[...folderName]]
.
Example:
Folder structure:
app/
└── shop/
└── [[...filters]]/
└── page.js
- This route matches
/shop
(no parameter). - It also matches
/shop/laptops
,/shop/laptops/apple
, ...
How to get the value:
// app/shop/[[...filters]]/page.js
export default function ShopPage({ params }) {
// For /shop, params: {}
// For /shop/laptops/apple, params: { filters: ['laptops', 'apple'] }
const { filters } = params
return (
<div>
{filters ? (
<h1>Filtering products by: {filters.join(' > ')}</h1>
) : (
<h1>Showing all products</h1>
)}
</div>
)
}
Performance Optimization with generateStaticParams
One of Next.js’s most powerful features is Static Site Generation (SSG). With Dynamic Routes, you can pre-generate static pages at build time for all possible parameters. This makes your site lightning fast and reduces server load.
The generateStaticParams
function lets you do this.
How it works:
- In the dynamic route’s
page.js
, export an async function calledgenerateStaticParams
. - This function returns an array of objects, each representing the
params
for a static page to generate.
Example: Pre-generate all blog post pages.
// app/blog/[slug]/page.js
// 1. Fetch all post slugs
async function getAllPostSlugs() {
const res = await fetch('https://api.example.com/posts')
const posts = await res.json()
// Return in the format generateStaticParams expects
return posts.map((post) => ({
slug: post.slug,
}))
}
// 2. Export generateStaticParams
export async function generateStaticParams() {
const slugs = await getAllPostSlugs()
return slugs
}
// The data fetch function and Page component remain as in the first example
async function getPostData(slug) {
/* ... */
}
export default async function BlogPostPage({ params }) {
/* ... */
}
When you run npm run build
, Next.js will:
- Call
generateStaticParams
. - Get a list like
[{ slug: 'post-a' }, { slug: 'post-b' }]
. - Render
/blog/post-a
and/blog/post-b
as static HTML files.
When users visit these URLs, they get the HTML instantly—no server render wait, for a blazing fast experience.
Note: If a user visits a slug
not generated by generateStaticParams
, Next.js will render that page on-demand, just like a normal Server Component.
Conclusion: The Power is in Your Hands
Dynamic Routes in Next.js are not just a technical feature—they’re a foundational tool for building complex, data-rich, scalable web apps. By combining intuitive folder structure with the power of Server Components and static page generation via generateStaticParams
, you can deliver fast, smooth, and SEO-optimized user experiences.
Hopefully, this article has given you a deep and comprehensive understanding of Dynamic Routes. Start applying them in your next Next.js project and unlock their endless possibilities!