Files
next.js/errors/sync-dynamic-apis.mdx
Arian Tron 61f56f997c
Some checks failed
Test examples / Test Examples (20) (push) Has been cancelled
Test examples / Test Examples (22) (push) Has been cancelled
Lock Threads / action (push) Has been cancelled
Trigger Release / start (push) Has been cancelled
Stale issue handler / stale (push) Has been cancelled
Update Font Data / create-pull-request (push) Has been cancelled
build-and-deploy / deploy-target (push) Has been cancelled
build-and-deploy / build (push) Has been cancelled
build-and-deploy / stable - aarch64-unknown-linux-musl - node@16 (push) Has been cancelled
build-and-deploy / stable - x86_64-unknown-linux-musl - node@16 (push) Has been cancelled
build-and-deploy / stable - aarch64-unknown-linux-gnu - node@16 (push) Has been cancelled
build-and-deploy / stable - x86_64-unknown-linux-gnu - node@16 (push) Has been cancelled
build-and-deploy / stable - aarch64-pc-windows-msvc - node@16 (push) Has been cancelled
build-and-deploy / stable - x86_64-pc-windows-msvc - node@16 (push) Has been cancelled
build-and-deploy / stable - aarch64-apple-darwin - node@16 (push) Has been cancelled
build-and-deploy / stable - x86_64-apple-darwin - node@16 (push) Has been cancelled
build-and-deploy / build-wasm (nodejs) (push) Has been cancelled
build-and-deploy / build-wasm (web) (push) Has been cancelled
build-and-deploy / Deploy preview tarball (push) Has been cancelled
build-and-deploy / Potentially publish release (push) Has been cancelled
build-and-deploy / publish-turbopack-npm-packages (push) Has been cancelled
build-and-deploy / Deploy examples (push) Has been cancelled
build-and-deploy / thank you, build (push) Has been cancelled
build-and-deploy / Upload Turbopack Bytesize metrics to Datadog (push) Has been cancelled
Rspack Next.js development integration tests / Rspack integration tests (push) Has been cancelled
Rspack Next.js production integration tests / Rspack integration tests (push) Has been cancelled
Turbopack Next.js development integration tests / Next.js integration tests (push) Has been cancelled
Turbopack Next.js production integration tests / Next.js integration tests (push) Has been cancelled
Update Rspack test manifest / Update and upload Rspack development test manifest (push) Has been cancelled
Update Rspack test manifest / Update and upload Rspack production test manifest (push) Has been cancelled
Upload bundler test manifests to areweturboyet.com / Upload test results (push) Has been cancelled
Update React / create-pull-request (push) Has been cancelled
test-e2e-project-reset-cron / reset-test-project (push) Has been cancelled
Notify about the top 15 issues/PRs/feature requests (most reacted) in the last 90 days / run (push) Has been cancelled
first commit
2026-03-10 19:37:31 +03:30

93 lines
3.4 KiB
Plaintext

---
title: Dynamic APIs are Asynchronous
description: Learn more about why accessing certain APIs synchronously now warns.
---
## Why This Warning Occurred
Somewhere in your code you used an API that opts into [dynamic rendering](/docs/app/glossary#dynamic-rendering).
Dynamic APIs are:
- The `params` and `searchParams` props that get provided to pages, layouts, metadata APIs, and route handlers.
- `cookies()`, `draftMode()`, and `headers()` from `next/headers`
In Next 15, these APIs have been made asynchronous. You can read more about this in the Next.js 15 [Upgrade Guide](/docs/app/guides/upgrading/version-15).
For example, the following code will issue a warning:
```jsx filename="app/[id]/page.js"
function Page({ params }) {
// direct access of `params.id`.
return <p>ID: {params.id}</p>
}
```
This also includes enumerating (e.g. `{...params}`, or `Object.keys(params)`) or iterating over the return
value of these APIs (e.g. `[...headers()]` or `for (const cookie of cookies())`, or explicitly with `cookies()[Symbol.iterator]()`).
## Possible Ways to Fix It
The [`next-async-request-api` codemod](/docs/app/guides/upgrading/codemods#next-async-request-api) can fix many of these cases automatically:
```bash filename="Terminal"
npx @next/codemod@canary next-async-request-api .
```
The codemod cannot cover all cases, so you may need to manually adjust some code.
If the warning occurred on the Server (e.g. a route handler, or a Server Component),
you must `await` the dynamic API to access its properties:
```jsx filename="app/[id]/page.js"
async function Page({ params }) {
// asynchronous access of `params.id`.
const { id } = await params
return <p>ID: {id}</p>
}
```
If the warning occurred in a synchronous component (e.g. a Client component),
you must use `React.use()` to unwrap the Promise first:
```jsx filename="app/[id]/page.js"
'use client'
import * as React from 'react'
function Page({ params }) {
// asynchronous access of `params.id`.
const { id } = React.use(params)
return <p>ID: {id}</p>
}
```
### Unmigratable Cases
If Next.js codemod found anything that is not able to be migrated by the codemod, it will leave a comment with `@next-codemod-error` prefix and the suggested action, for example:
In this case, you need to manually await the call to `cookies()`, and change the function to async. Then refactor the usages of the function to be properly awaited:
```ts
export function MyCookiesComponent() {
const c =
/* @next-codemod-error Manually await this call and refactor the function to be async */
cookies()
return c.get('name')
}
```
### Enforced Migration with Linter
If you didn't address the comments that starting with `@next-codemod-error` left by the codemod, Next.js will error in both dev and build to enforce you to address the issues.
You can review the changes and follow the suggestion in the comments. You can either make the necessary changes and remove the comment, or replace the comment prefix `@next-codemod-error` with `@next-codemod-ignore`
If there's no action to be taken, the comment prefix `@next-codemod-ignore` will bypass the build error.
```diff
- /* @next-codemod-error <suggested message> */
+ /* @next-codemod-ignore */
```
> **Good to know**:
>
> You can delay unwrapping the Promise (either with `await` or `React.use`) until you actually need to consume the value.
> This will allow Next.js to statically render more of your page.