Description
Breaking changes after v15.0.0-canary.171
As of version v15.0.0-canary.171
, we’ve introduced several breaking changes to the Next.js APIs in #68812, particularly those related to dynamic rendering. The critical change involves making dynamic APIs asynchronous to improve flexibility and enable new features in future versions. This update includes changes to cookies()
, headers()
, draftMode()
, searchParams
, and params
.
We plan to release this change as part of a new Release Candidate (RC2) for Next.js 15 in the coming weeks after we've validated the changes internally and with our early users.
To help you migrate smoothly, follow the instructions below, including using a codemod and manual adjustments where necessary.
Breaking Changes Overview
1. Dynamic APIs Now Return Promises
Most dynamic APIs (e.g., cookies()
, headers()
, draftMode()
, searchParams
, and params
) now return Promises instead of values synchronously. This enables more powerful rendering patterns in Next.js by separating prerender time from render time.
Updated APIs:
cookies()
: Now returnsPromise<ReadonlyRequestCookies>
headers()
: Now returnsPromise<ReadonlyHeaders>
draftMode()
: Now returnsPromise<DraftMode>
searchParams
: Now a Promise, e.g.,Promise<{ foo: string }>
params
: Now a Promise, e.g.,Promise<{ foo: string }>
Codemod for Automatic Migration
We’ve provided a codemod to help automate most of the updates required for this migration.
1. Run the Codemod
Run the following command to update your codebase for the new async API usage automatically:
npx @next/codemod@canary next-async-request-api .
This will convert your synchronous use of cookies()
, headers()
, draftMode()
, searchParams
, and params
into asynchronous use, as shown below.
2. Preferred Usage (Async)
Once the codemod is applied, your code should look something like this:
// Async usage (preferred)
const token = (await cookies()).get('token');
const header = (await headers()).get('x-foo');
if ((await draftMode()).isEnabled) { ... }
Manual Adjustments
Manual changes will sometimes be necessary, mainly if your code relies on custom types or more complex logic.
For example, in TypeScript:
import { type UnsafeUnwrappedCookies } from 'next/headers';
const token = (cookies() as unknown as UnsafeUnwrappedCookies).get('token');
Ensure that any custom props or types you’ve created are updated to reflect the new Promise
-based return types for searchParams
and params
.
TypeScript Changes
New type restrictions apply to searchParams
and params
. If you rely on strict typing, these changes will require manual fixes in your codebase.
searchParams
: The new type isPromise<any>
, with plans to move towardsURLSearchParams
.params
: The type is nowPromise<{[key: string]: string | string[] | undefined }>
, enforcing stricter control over the params used in various segments.
Temporary Synchronous Usage (Discouraged)
If you can’t immediately switch to async, you can temporarily use synchronous access, but this will trigger a dev warning:
// Temporary sync usage
const token = cookies().get('token');
However, this path will be deprecated soon, so we recommend switching to async as quickly as possible.
Additional Resources
For more details on these breaking changes, please refer to @gnoff's PR introducing them: #68812. We will also have more information in our documentation in the coming days.
If you happen to have any issues or have specific questions, please feel free to comment on this issue or open a new one for further assistance.