You asked your AI coding agent for a product page at app/products/[id]/page.js. It wrote params.id the way every tutorial does, and the page even loads. But the terminal prints a warning about params needing to be awaited, and in some setups the build stops on it. The code looks right, and a year ago it was right.
The cause is a change in Next.js 15, and the fix is a single await.
Why this happens
In Next 15, the Next.js docs say, a group of “dynamic APIs” became asynchronous. They are:
- The
paramsandsearchParamsprops given to pages, layouts, metadata APIs and route handlers cookies(),draftMode()andheaders()fromnext/headers
Before Next 15 you could read params.id directly. Now params is a Promise. Agents learned from a lot of Next 13 and 14 code, so they keep writing the old synchronous form, and the framework warns you about it.
The docs also point out that enumerating these values counts as direct access: {...params}, Object.keys(params), [...headers()] and for (const cookie of cookies()) all trigger the same warning.
How to tell if this is your problem
- Check your version. Run
npx next --version. If it is 15 or higher, this applies. - Read the warning. It is titled “Dynamic APIs are Asynchronous” in the Next.js docs and points at the file that touched
params,searchParams,cookies()orheaders(). - Open that file and look for
params.somethingor a barecookies().get(...)with noawait.
The fix
In a Server Component, make the function async and await the value. This is the pattern from the Next.js docs:
async function Page({ params }) {
const { id } = await params
return <p>ID: {id}</p>
}
The same goes for cookies() and headers(): write const cookieStore = await cookies(), then read from cookieStore.
If the component is a Client Component, it cannot be async. The docs say to unwrap the Promise with React.use():
'use client'
import * as React from 'react'
function Page({ params }) {
const { id } = React.use(params)
return <p>ID: {id}</p>
}
Let the codemod do the bulk of it
Next.js ships a codemod for exactly this migration:
npx @next/codemod@canary next-async-request-api .
The docs say it fixes many cases but not all. Where it cannot migrate a call, it leaves a comment starting with @next-codemod-error and a suggested action, such as a helper function that calls cookies() and must become async. Next.js then errors in both dev and build until you handle each one. Make the helper async, await its callers, and remove the comment. If nothing needs doing, you can replace the prefix with @next-codemod-ignore to pass the build.
Do not unwrap too early
The docs add one tip: you can delay awaiting the Promise until you actually need the value. That lets Next.js statically render more of the page. If only one small component needs searchParams, pass the Promise down and await it there, rather than awaiting at the top of the page.
How to avoid this next time
Tell the agent your version up front: “This is Next.js 15 App Router. params, searchParams, cookies() and headers() are async, so await them in Server Components and use React.use() in Client Components.” In review, search the diff for params. and cookies() and check that each one is awaited or unwrapped.
Comments
Sign in to join the conversation.
No comments yet — be the first.