params Is a Promise Now
Back to blog

Article

params Is a Promise Now

The Next.js upgrade note that breaks the most files at once, and the two-line fix.

August 5, 20261 min readNext.jsTypeScript

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:

tsx
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:

tsx
export default async function Page({
  searchParams,
}: {
  searchParams: Promise<{ q?: string }>
}) {
  const { q } = await searchParams
}

Two things worth knowing:

  • The page function has to be async to await them. Static pages that never touched async are the ones this catches.
  • Awaiting 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.

Keep Reading

More from the blog.

Every Post

The full list of posts lives on the blog index.

Back to blog