Next.js Dynamic Routes
Dynamic routes let you create one page template that works for many different URLs. Instead of making a separate page for each blog post, you create one dynamic page that handles all of them. The URL changes, but the same file handles every request.
The Problem Dynamic Routes Solve
Imagine a blog with 500 posts. Without dynamic routes, you would need 500 separate page files. That is not practical. Dynamic routes let you create one file and use the URL itself to decide what content to show.
WITHOUT DYNAMIC ROUTES (impractical): app/blog/post-1/page.js app/blog/post-2/page.js app/blog/post-3/page.js ... 500 more files WITH DYNAMIC ROUTES (practical): app/blog/[slug]/page.js ← One file handles all posts
Creating a Dynamic Route
Wrap the folder name in square brackets to make it dynamic. The name inside the brackets becomes a variable called a parameter.
app/blog/[slug]/page.js
This single file now responds to:
yoursite.com/blog/hello-world yoursite.com/blog/my-first-post yoursite.com/blog/nextjs-tutorial
Reading the Dynamic Parameter
Inside your page file, Next.js passes the dynamic value through a params object. You access it like this:
export default function BlogPost({ params }) {
return (
<main>
<h1>Post: {params.slug}</h1>
</main>
);
}
If someone visits /blog/hello-world, the value of params.slug is "hello-world".
Diagram: How Parameters Flow
USER VISITS: /blog/learn-nextjs
↓
NEXT.JS READS: app/blog/[slug]/page.js
↓
PASSES TO COMPONENT:
params = { slug: "learn-nextjs" }
↓
COMPONENT USES: params.slug → "learn-nextjs"
↓
SHOWS: The content for that specific post
Using the Parameter to Fetch Data
The real power of dynamic routes appears when you fetch data using the parameter. Here is a practical example:
export default async function BlogPost({ params }) {
const post = await fetch(`https://api.example.com/posts/${params.slug}`);
const data = await post.json();
return (
<main>
<h1>{data.title}</h1>
<p>{data.body}</p>
</main>
);
}
Every time someone visits a different blog post URL, the same file runs but fetches different data based on the slug.
Multiple Dynamic Segments
You can have more than one dynamic segment in a URL by nesting dynamic folders.
app/shop/[category]/[product]/page.js
Matches:
/shop/electronics/iphone
/shop/clothing/blue-shirt
/shop/books/nextjs-guide
params = { category: "electronics", product: "iphone" }
Catch-All Routes
Use three dots inside the brackets to match any number of URL segments:
app/docs/[...slug]/page.js Matches: /docs/getting-started /docs/api/reference /docs/api/components/button params.slug = ["api", "components", "button"]
Diagram: Static vs Dynamic Routes Side by Side
STATIC ROUTE: app/about/page.js → always shows /about page (one URL, one page) DYNAMIC ROUTE: app/blog/[slug]/page.js → handles /blog/ANY-VALUE (one file, many URLs)
Key Takeaway
Dynamic routes use square brackets around a folder name to capture variable URL segments. One file handles many different URLs. The captured value arrives in your component through the params object, and you use it to show the right content.
