Route used `params.id`. `params` should be awaited before using its properties

Filed under Next.js & React errors

Most likely causeAbout 10 min · 6 steps

Next.js 15 changed params from a plain object into a promise, so reading params.id directly no longer works the old way — you have to await it first.

Make the page or handler async
Await params before reading it
Client Component? Use React use()

Fastest route

Give your AI this prompt

Copy it, replace the bracketed part with your error, and send it.

Preview the prompt
My Next.js 15 app logs this error: "Route '/[paste your route]' used `params.[property]`. `params` should be awaited before using its properties." (It may also mention searchParams or sync-dynamic-apis.)

Here is the file the error points at: [paste the page, layout, generateMetadata, or route handler].

Please: 1) if it is a server component or route handler, make the function async, await params (and searchParams if present) before any property is read, and update the TypeScript type to Promise<{ ... }> with my real segment names, 2) if it is a Client Component, unwrap the promise with React's use() instead of await, 3) search the rest of the project for other direct params. or searchParams. reads in the old synchronous style and list them for me.

Constraints: do not change the route structure, the data fetching, or what the page renders — only how params and searchParams are unwrapped. Show me each file you change.

Fix it yourself

Follow the repair

  1. In a server page or layout, make the function async and await params. This one edit clears the error in the overwhelming majority of cases:
    // Before (Next.js 14 style — triggers the error in 15)
    export default function Page({ params }) {
      return <h1>Post {params.id}</h1>;
    }
    
    // After — same page, awaited
    export default async function Page({ params }) {
      const { id } = await params;
      return <h1>Post {id}</h1>;
    }
    With TypeScript, the prop type changes to match: params: Promise<{ id: string }>, using your real segment names.
  2. Apply the same pattern in generateMetadata. Metadata functions receive params too, and they are easy to forget because the page itself looks fixed. Make generateMetadata async and await params at its top, exactly like the page. If the error names a route but the page looks clean, the metadata function is the usual hiding place.
  3. In a route handler, await the params from the context argument. Handlers receive params the same way:
    export async function GET(request, { params }) {
      const { id } = await params;
      // use id as a normal value from here on
    }
    One await, at the top, before any property is read — partial fixes, like awaiting after a synchronous read, still trip the error.
  4. In a Client Component, use React's use() instead of await. Client Components cannot be declared async, so the promise is unwrapped differently:
    "use client";
    import { use } from "react";
    
    export default function Page({ params }) {
      const { id } = use(params);
      return <h1>Post {id}</h1>;
    }
    Same idea, different tool: use() reads the resolved value during render. Do not reach for useEffect-and-state workarounds here — use() is the intended pattern.
  5. Give searchParams the identical treatment. Whatever you did for params, do for searchParams: await it in server components, use() it in client components, and type it as a Promise. People routinely fix one, watch the error halve, and assume something else broke — it is the same change wearing a second name tag.
  6. Sweep the whole project for leftovers. Search your codebase for params. and searchParams. and check each hit sits below an await or inside use(). Next.js also ships an official codemod for this migration — npx @next/codemod@canary next-async-request-api — which rewrites the common patterns automatically; on a large upgraded project it beats hand-editing thirty files.
Why this happensOptional explanation

In Next.js 14 and earlier, a dynamic page like /posts/[id] received params as a plain object: you wrote params.id and got the value. In Next.js 15, params arrives as a promise of that object. The values are all still there — they are just one await away. Next.js made the change so pages can start rendering before every request detail is resolved, which makes streaming and partial rendering faster. Reading the property synchronously, the old way, now triggers the error you are seeing.

This error ambushes people mid-upgrade in particular. The code worked yesterday, the upgrade changed nothing about the routes, and suddenly the console fills with complaints about code nobody touched. It is not a bug in your app and not really a bug in Next.js either — it is a deliberate breaking change with a deliberate error message, and in current versions the old access still functions while logging the error, as a grace period before it is removed. Fixing it is a find-and-repeat job, not a redesign.

  • Recent upgrade: the app moved from Next.js 14 to 15 and every params read predates the change.
  • AI-generated code in the old style: AI builders frequently write the Next.js 14 pattern from memory, even in brand-new Next.js 15 projects.
  • searchParams too: the same change applies to searchParams, and its version of the error surprises people who fixed params and stopped reading.
  • Every receiver counts: pages, layouts, generateMetadata, and route handlers all get the promise form — miss one and the error follows you there.

Quick answers

Do I have to change every page that reads params?

Yes. Most code updates mechanically: make the function async and await the promise once, then use the values as plain variables. Layouts, generateMetadata, and route handlers follow the same pattern — the official codemod (npx @next/codemod@canary next-async-request-api) can apply it across a whole project.

Is this an error or a warning? My page still works.

It is. Next.js prints it as an error in development so you fix it before upgrading further: in the current version the synchronous access still works after logging the complaint, but it is scheduled for removal, and the console noise hides real errors. Treat it as a to-do the framework is serious about.

Does searchParams have the same problem?

Yes — in Next.js 15, both are promises now. searchParams in pages follows the same rule: await it in a server page, or unwrap it with use() in a Client Component. It catches people out because params gets all the attention in the error messages.

One fix, every Friday.

One real error, explained in plain English, with the fix — in your inbox every Friday. No spam, no jargon, unsubscribe anytime.