Menu
Coddy logo textTech

Awaiting Route Params

Part of the Next.js Essentials section of Coddy's React journey — lesson 24 of 47.

A dynamic route hands your page the URL segment through params. In Next 15 there is a catch worth memorising:

params is a promise.

// app/menu/[slug]/page.jsx
export default async function DishPage({ params }) {
    const { slug } = await params;
    // /menu/carbonara  ->  slug === 'carbonara'
}

Forget the await and nothing crashes, which is exactly what makes it sneaky. Destructuring a promise just gives you undefined:

const { slug } = params;   // undefined
const dish = await getDish(slug);   // looks up nothing

The page still renders. It's just blank, or full of fallbacks, and you go hunting through your data layer for a bug that was never there.

The same rule applies to searchParams. Both are promises, both need awaiting, and both are only available to async server components, one more reason the page you just wrote had to be async.

Why promises at all? So Next.js can start rendering the parts of your page that don't depend on the URL before it has finished working out the parts that do.

challenge icon

Challenge

Easy

app/menu/[slug]/page.jsx is nearly right, but it never awaits params, so every dish comes back as Unknown dish.

  1. Await params before destructuring: const { slug } = await params;

lib/data.js and the home page are locked. Visiting /menu/carbonara must show Carbonara in #dish-name and its price in #dish-price.

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>
    );
}
quiz iconTest yourself

This lesson includes a short quiz. Start the lesson to answer it and track your progress.

All lessons in Next.js Essentials