Dynamic Routes
Part of the Next.js Essentials section of Coddy's React journey — lesson 8 of 47.
A menu with forty dishes doesn't get forty folders. You want /menu/pizza, /menu/pasta and /menu/tiramisu to be the same page showing different data.
That's what square brackets in a folder name mean:
app/
menu/
[slug]/
page.jsx -> /menu/pizza
-> /menu/pasta
-> /menu/anything-at-allA normal folder matches its own name. A [bracketed] folder matches any segment and remembers what it matched. The word inside the brackets is the name you'll read it back by: [slug] gives you slug, [id] gives you id.
Next hands that value to the page as a prop called params:
// app/menu/[slug]/page.jsx
export default async function Dish({ params }) {
const { slug } = await params;
return <h1>{slug}</h1>;
}Three things happen in that tiny file:
- The page takes a
paramsprop. Every page gets one, and for a dynamic route it holds the matched segments. paramsis a Promise in Next 15, so youawaitit. That's why the component isasync. Chapter 5 explains why pages are allowed to be.- Destructuring pulls out
slug, whose name comes straight from the folder[slug].
Visit /menu/pasta and slug is "pasta". One file, every dish.
Challenge
EasyThe dynamic folder is already there: app/menu/[slug]/page.jsx answers every URL under /menu. Trouble is, it says pizza no matter which dish you asked for.
- Make the component
async. - Read the matched segment with
const { slug } = await params;. - Render
sluginside the<h1 id="dish">instead of the hardcoded text.
The tests visit two different dishes and expect two different headings.
Try it yourself
import './globals.css';
export const metadata = {
title: 'My App',
};
export default function RootLayout({ children }) {
return (
<html lang="en">
<body>
{children}
</body>
</html>
);
}This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Next.js Essentials
2Routing & Links
Folders Are RoutesNested RoutesLinking PagesDynamic RoutesNot Found PagesRecap: Routing