In short
You can't make a separate file for every blog post or product. Dynamic routes let one file handle thousands of URLs, each with its own data.
Routes with a variable segment (`[slug]`, `[id]`) that map a single file to many URLs — the basis of blog posts, product pages and user profiles.

Think of it like this
Train coach and berth numbers
Every coach has the same layout. Only the number changes: S4, berth 32. The railway doesn't build a new coach design per passenger. One page file is the coach design, and the slug or id in the URL is your berth number.
Watch it happen
One file, many colleges
GET /colleges/iim-a
1/6The URL matches app/colleges/[slug], so slug is iim-a.
The big ideas
What you need to know
Square brackets
app/blog/[slug]/page.tsx matches /blog/anything and gives you slug as a param.
params is a Promise
Since Next.js 15, you await params before reading values: const { slug } = await params.
Catch-all routes
[...slug] matches many segments, like /docs/a/b/c, and gives you an array.
notFound()
If no data exists for that slug, call notFound() to show your 404 page.
See it in code
Walk through the code
1// app/colleges/[slug]/page.tsx2import { notFound } from "next/navigation";3import { getCollege } from "@/lib/colleges";4 5type Props = { params: Promise<{ slug: string }> };6 7export default async function CollegePage({ params }: Props) {8 const { slug } = await params;9 const college = await getCollege(slug);10 if (!college) notFound();11 12 return <h1>{college.name}, {college.city}</h1>;13}1/4params is a Promise holding the slug from the URL.
/colleges/iim-ahmedabad gives slug = "iim-ahmedabad". Unknown slugs get a proper 404 instead of a crash.
Save yourself the pain
Common mistakes
Oops
Using numeric ids in public URLs like /colleges/482.
Do this instead
Use readable slugs like /colleges/iim-ahmedabad. They're better for users and search results.
Oops
Rendering an empty page when the slug doesn't exist.
Do this instead
Call notFound() so users and Google get a real 404.
Your mission
Profile pages for your friends
Quick check
Which folder name matches both /docs/setup and /docs/setup/linux/install?
Go deeper
- 1Build a `[slug]/page.tsx` route and read the param with the `params` prop.
- 2Learn catch-all routes (`[...slug]`) for arbitrarily nested paths.
- 3Combine dynamic routes with `generateStaticParams` to pre-render known pages.
More topics at this stop
Stuck on this topic? Ask an Insider
Get 1:1 guidance from people who've walked this exact path — on the InsideEdge app.