Error: Route used `searchParams.X`. `searchParams` should be awaited before using its properties.
ID: nextjs/searchparams-sync-access
Version Compatibility
| Version | Status | Introduced | Deprecated | Notes |
|---|---|---|---|---|
| 14 | active | — | — | — |
Root Cause
Next.js 15 changed searchParams and params from synchronous objects to Promises. Code that accesses searchParams.X directly without awaiting will fail. This is a breaking change from Next.js 14.
genericWorkarounds
-
96% success Await searchParams before accessing its properties in Server Components
// Next.js 15+ page.tsx export default async function Page({ searchParams, }: { searchParams: Promise<{ q?: string }> }) { const params = await searchParams; const query = params.q; return <div>Search: {query}</div>; }Sources: https://nextjs.org/docs/app/api-reference/file-conventions/page#searchparams-optional https://nextjs.org/blog/next-15#async-request-apis-breaking-change
-
90% success Use React.use() to unwrap the searchParams promise in Client Components
'use client'; import { use } from 'react'; export default function Page({ searchParams, }: { searchParams: Promise<{ q?: string }> }) { const params = use(searchParams); return <div>Search: {params.q}</div>; }Sources: https://nextjs.org/blog/next-15#async-request-apis-breaking-change
-
92% success Use the next/headers cookies() and headers() with await as well during migration
// Next.js 15: all request APIs are now async import { cookies, headers } from 'next/headers'; export default async function Page({ searchParams, }: { searchParams: Promise<{ q?: string }> }) { const [params, cookieStore, headerList] = await Promise.all([ searchParams, cookies(), headers(), ]); // use params.q, cookieStore.get('token'), etc. }Sources: https://nextjs.org/blog/next-15#async-request-apis-breaking-change
Dead Ends
Common approaches that don't work:
-
Downgrade to Next.js 14 to avoid the breaking change
70% fail
Downgrading avoids the immediate error but locks the project out of Next.js 15 features and security updates. The migration is straightforward and should be done instead.
-
Type searchParams as a plain object (e.g., { X: string }) without Promise
92% fail
TypeScript types may suppress editor errors, but at runtime searchParams is still a Promise. Accessing properties without await returns undefined or throws.
-
Use useSearchParams() hook in a Server Component to get synchronous access
88% fail
useSearchParams() is a Client Component hook and cannot be used in Server Components. In Server Components, the only way to access search params is through the page/layout props which are now Promises.