
Article
The Next.js upgrade note that breaks the most files at once, and the two-line fix.
Dynamic APIs in the App Router are async. params, searchParams, cookies(), and headers() all return promises, and reading them synchronously is a type error before it is a runtime one.
The shape every dynamic route now takes:
export default async function Page({
params,
}: {
params: Promise<{ slug: string }>
}) {
const { slug } = await params
return <Article slug={slug} />
}generateMetadata takes the same treatment, and so does searchParams:
export default async function Page({
searchParams,
}: {
searchParams: Promise<{ q?: string }>
}) {
const { q } = await searchParams
}Two things worth knowing:
async to await them. Static pages that never touched async are the ones this catches.searchParams opts the route into dynamic rendering. If a param is only used for a redirect, that cost is real — check whether it belongs in the route segment instead.The mechanical fix is a Promise<> wrapper and an await. The thing actually worth reading is the upgrade guide, because this rarely arrives alone.
More from the blog.
The full list of posts lives on the blog index.
Back to blog