Chapter 03 — Routing Deep Dive: Dynamic, Nested & Catch-All Routes
Chapter 03 — Routing Deep Dive: Dynamic, Nested & Catch-All Routes
Hey everyone! Now that you know a folder = a route, let's go deeper. Real apps need more than static paths like /about — they need /blog/my-post, /shop/electronics/laptops, and URLs whose structure you don't know in advance. Next.js handles all of it, still with plain folder names.
What we will cover:
- Dynamic segments —
[param] - Reading route params in a page
- Catch-all and optional catch-all routes
- Nested routes and how layouts stack
Linkvs<a>— why it matters- Programmatic navigation with
useRouter
1. Dynamic Segments — [param]
app/
└── blog/
└── [slug]/
└── page.js
Visiting:
/blog/hello-world → slug = "hello-world"
/blog/react-tips → slug = "react-tips"
One file. Infinite URLs.
// app/blog/[slug]/page.js
export default async function BlogPost({ params }) {
const { slug } = await params; // Next.js 15: params is a Promise
return <h1>Post: {slug}</h1>;
}
Note: starting Next.js 15, params (and searchParams) are async — you must await them. This trips up a lot of people copying older tutorials.
2. Multiple Dynamic Segments
app/
└── shop/
└── [category]/
└── [product]/
└── page.js
/shop/electronics/laptop-15 → category = "electronics", product = "laptop-15"
export default async function ProductPage({ params }) {
const { category, product } = await params;
...
}
3. Catch-All Routes — [...param]
app/
└── docs/
└── [...slug]/
└── page.js
/docs/a → slug = ["a"]
/docs/a/b → slug = ["a", "b"]
/docs/a/b/c → slug = ["a", "b", "c"]
One file, matches ANY depth after /docs/.
Great for documentation sites with nested pages.
4. Optional Catch-All — [[...param]]
app/
└── shop/
└── [[...filters]]/
└── page.js
/shop → filters = undefined ← the DOUBLE brackets make /shop itself match too
/shop/shoes → filters = ["shoes"]
/shop/shoes/nike → filters = ["shoes", "nike"]
Difference from [...param]: without the extra brackets, "/shop"
alone (with NO segments after it) would 404. Double brackets fix that.
5. Nested Routes & How Layouts Stack
app/
├── layout.js ← wraps EVERYTHING (root layout, required)
├── dashboard/
│ ├── layout.js ← wraps everything under /dashboard
│ ├── page.js ← "/dashboard"
│ └── settings/
│ └── page.js ← "/dashboard/settings"
Visiting /dashboard/settings renders:
RootLayout(
DashboardLayout(
SettingsPage()
)
)
Every layout above a route wraps it. This is how a shared
sidebar/navbar for a whole section works — one layout.js,
automatically applied to every page beneath it.
6. Link vs Plain <a>
❌ <a href="/about">About</a>
→ full page reload, browser re-downloads everything, SLOW
✅ import Link from "next/link";
<Link href="/about">About</Link>
→ client-side navigation, no full reload
→ Next.js automatically PREFETCHES the linked page in the
background when it scrolls into view, so the click feels instant
Always use Link for internal navigation. It's not a style preference — plain <a> throws away the SPA-like fast navigation Next.js gives you for free.
7. Programmatic Navigation — useRouter
"use client";
import { useRouter } from "next/navigation";
function LoginButton() {
const router = useRouter();
async function handleLogin() {
await loginUser();
router.push("/dashboard"); // navigate after an action
// router.replace("/dashboard") → like push, but no back-button history
// router.refresh() → re-fetch server data for current route
}
return <button onClick={handleLogin}>Log In</button>;
}
⚠️ Note the import: next/navigation, not the old next/router (that's the Pages Router version and won't work here).
Key Points to Remember
[param]= one dynamic segment,[...param]= catch-all,[[...param]]= optional catch-all- In Next.js 15+,
paramsandsearchParamsare async — alwaysawaitthem - Layouts nest and stack — every layout above a route automatically wraps it
- Always use
<Link>for internal links — it enables client-side nav + prefetching - Use
useRouterfromnext/navigationfor navigation triggered by code (after form submit, etc.)
What's Next?
Next chapter, we tackle the single biggest mental shift coming from plain React: Server Components vs Client Components — what runs where, and why it matters.
Keep coding, keep learning! See you in the next one!
Post a Comment