Skip to content

Guide: Fixing breaking changes after v15.0.0-canary.171 #70899

Closed
@feedthejim

Description

@feedthejim

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 returns Promise<ReadonlyRequestCookies>
  • headers(): Now returns Promise<ReadonlyHeaders>
  • draftMode(): Now returns Promise<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 is Promise<any>, with plans to move towards URLSearchParams.
  • params: The type is now Promise<{[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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    linear: nextConfirmed issue that is tracked by the Next.js team.locked

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions