You’ve seen them. URLs like /blog/how-to-nextjs
or /user/42
that magically load the right content. That’s not sorcery — it’s just Next.js doing what it does best: mapping routes to data with minimal fuss.
Instead of hardcoding every possible path, you can use dynamic routing. It’s efficient, scalable, and downright essential once your site grows past a handful of static pages.
What are dynamic routes?
In Next.js, you define dynamic pages using square brackets in your filenames. For instance, pages/blog/[slug].js
handles any URL like /blog/my-article
, pulling the right content based on the URL parameter.
Basic Dynamic Route Example (pages/
directory)
File Structure:
pages/ blog/ [slug].js
Code:
// pages/blog/[slug].js import { useRouter } from 'next/router'; export default function BlogPost() { const router = useRouter(); const { slug } = router.query; return <h1>Blog Post: {slug}</h1>; }
When someone visits /blog/hello-world
, they’ll see:
Blog Post: hello-world
One file, infinite possibilities.
Dynamic Route with getStaticPaths
+ getStaticProps
(SSG)
Want SEO, speed, and a sprinkle of magic? This combo pre-builds each route at compile time.
export async function getStaticPaths() { const posts = await fetchAllSlugs(); // ['hello-world', 'nextjs-rocks'] return { paths: posts.map((slug) => ({ params: { slug } })), fallback: 'blocking', // or false for 404 on unknown slugs }; } export async function getStaticProps({ params }) { const post = await fetchPostBySlug(params.slug); return { props: { post } }; }
This is how you bake dynamic pages into your static site, fast, preloaded, and without client-side loading hiccups.
Dynamic Route with the app/
Directory
File Structure
app/ blog/ [slug]/ page.tsx
Code
// app/blog/[slug]/page.tsx import { getPostBySlug } from '@/lib/posts'; type Props = { params: { slug: string }; }; export default async function BlogPost({ params }: Props) { const post = await getPostBySlug(params.slug); return ( <article> <h1>{post.title}</h1> <p>{post.content}</p> </article> ); }
No useRouter
, no getStaticProps
, no getStaticPaths
. Just grab your params.slug
and go. It’s beautifully server-side, with minimal overhead.
Catch-All & Optional Catch-All Routes
Sometimes you need to go deeper, like /docs/a/b/c
.
Catch-All
pages/docs/[...slug].js
Matches /docs/a
, /docs/a/b
, etc.
Optional Catch-All
pages/docs/[[...slug]].js
Also matches /docs/
. Handy for pages where the path might or might not be nested.
What’s Next?
Dynamic routes are your first real taste of building flexible, real-world pages in Next.js. You’ve now got the tools to power anything from a blog to a product catalog.
Coming Soon: React Server Components in the Wild
In the next chapter, we’ll explain how React Server Components work, how to fetch data directly inside components, and how they help keep your bundle lean and fast. You bring the coffee, we’ll bring the code. Let’s ship.