This commit is contained in:
Kismet Hasanaj
2026-05-02 20:07:02 +02:00
parent ce8672e283
commit 34dc9aec52
9428 changed files with 1733330 additions and 0 deletions
+721
View File
@@ -0,0 +1,721 @@
---
title: Codemods
description: Use codemods to upgrade your Next.js codebase when new features are released.
---
Codemods are transformations that run on your codebase programmatically. This allows a large number of changes to be programmatically applied without having to manually go through every file.
Next.js provides Codemod transformations to help upgrade your Next.js codebase when an API is updated or deprecated.
## Usage
In your terminal, navigate (`cd`) into your project's folder, then run:
```bash filename="Terminal"
npx @next/codemod <transform> <path>
```
Replacing `<transform>` and `<path>` with appropriate values.
- `transform` - name of transform
- `path` - files or directory to transform
- `--dry` Do a dry-run, no code will be edited
- `--print` Prints the changed output for comparison
## Upgrade
Upgrades your Next.js application, automatically running codemods and updating Next.js, React, and React DOM.
```bash filename="Terminal"
npx @next/codemod upgrade [revision]
```
### Options
- `revision` (optional): Specify the upgrade type (`patch`, `minor`, `major`), an NPM dist tag (e.g. `latest`, `canary`, `rc`), or an exact version (e.g. `15.0.0`). Defaults to `minor` for stable versions.
- `--verbose`: Show more detailed output during the upgrade process.
For example:
```bash filename="Terminal"
# Upgrade to the latest patch (e.g. 16.0.7 -> 16.0.8)
npx @next/codemod upgrade patch
# Upgrade to the latest minor (e.g. 15.3.7 -> 15.4.8). This is the default.
npx @next/codemod upgrade minor
# Upgrade to the latest major (e.g. 15.5.7 -> 16.0.7)
npx @next/codemod upgrade major
# Upgrade to a specific version
npx @next/codemod upgrade 16
# Upgrade to the canary release
npx @next/codemod upgrade canary
```
> **Good to know**:
>
> - If the target version is the same as or lower than your current version, the command exits without making changes.
> - During the upgrade, you may be prompted to choose which Next.js codemods to apply and run React 19 codemods if upgrading React.
## Codemods
### 16.0
#### Remove `experimental_ppr` Route Segment Config from App Router pages and layouts
##### `remove-experimental-ppr`
```bash filename="Terminal"
npx @next/codemod@latest remove-experimental-ppr .
```
This codemod removes the `experimental_ppr` Route Segment Config from App Router pages and layouts.
```diff filename="app/page.tsx"
- export const experimental_ppr = true;
```
#### Remove `unstable_` prefix from stabilized API
##### `remove-unstable-prefix`
```bash filename="Terminal"
npx @next/codemod@latest remove-unstable-prefix .
```
This codemod removes the `unstable_` prefix from stabilized API.
For example:
```ts
import { unstable_cacheTag as cacheTag } from 'next/cache'
cacheTag()
```
Transforms into:
```ts
import { cacheTag } from 'next/cache'
cacheTag()
```
#### Migrate from deprecated `middleware` convention to `proxy`
##### `middleware-to-proxy`
```bash filename="Terminal"
npx @next/codemod@latest middleware-to-proxy .
```
This codemod migrates projects from using the deprecated `middleware` convention to using the `proxy` convention. It:
- Renames `middleware.<extension>` to `proxy.<extension>` (e.g. `middleware.ts` to `proxy.ts`)
- Renames named export `middleware` to `proxy`
- Renames Next.js config property `experimental.middlewarePrefetch` to `experimental.proxyPrefetch`
- Renames Next.js config property `experimental.middlewareClientMaxBodySize` to `experimental.proxyClientMaxBodySize`
- Renames Next.js config property `experimental.externalMiddlewareRewritesResolve` to `experimental.externalProxyRewritesResolve`
- Renames Next.js config property `skipMiddlewareUrlNormalize` to `skipProxyUrlNormalize`
For example:
```ts filename="middleware.ts"
import { NextResponse } from 'next/server'
export function middleware() {
return NextResponse.next()
}
```
Transforms into:
```ts filename="proxy.ts"
import { NextResponse } from 'next/server'
export function proxy() {
return NextResponse.next()
}
```
#### Migrate from `next lint` to ESLint CLI
##### `next-lint-to-eslint-cli`
```bash filename="Terminal"
npx @next/codemod@canary next-lint-to-eslint-cli .
```
This codemod migrates projects from using `next lint` to using the ESLint CLI with your local ESLint config. It:
- Creates an `eslint.config.mjs` file with Next.js recommended configurations
- Updates `package.json` scripts to use `eslint .` instead of `next lint`
- Adds necessary ESLint dependencies to `package.json`
- Preserves existing ESLint configurations when found
For example:
```json filename="package.json"
{
"scripts": {
"lint": "next lint"
}
}
```
Becomes:
```json filename="package.json"
{
"scripts": {
"lint": "eslint ."
}
}
```
And creates:
```js filename="eslint.config.mjs"
import { dirname } from 'path'
import { fileURLToPath } from 'url'
import { FlatCompat } from '@eslint/eslintrc'
const __filename = fileURLToPath(import.meta.url)
const __dirname = dirname(__filename)
const compat = new FlatCompat({
baseDirectory: __dirname,
})
const eslintConfig = [
...compat.extends('next/core-web-vitals', 'next/typescript'),
{
ignores: [
'node_modules/**',
'.next/**',
'out/**',
'build/**',
'next-env.d.ts',
],
},
]
export default eslintConfig
```
### 15.0
#### Transform App Router Route Segment Config `runtime` value from `experimental-edge` to `edge`
##### `app-dir-runtime-config-experimental-edge`
> **Note**: This codemod is App Router specific.
```bash filename="Terminal"
npx @next/codemod@latest app-dir-runtime-config-experimental-edge .
```
This codemod transforms [Route Segment Config `runtime`](https://nextjs.org/docs/app/api-reference/file-conventions/route-segment-config/runtime) value `experimental-edge` to `edge`.
For example:
```ts
export const runtime = 'experimental-edge'
```
Transforms into:
```ts
export const runtime = 'edge'
```
#### Migrate to async Dynamic APIs
APIs that opted into dynamic rendering that previously supported synchronous access are now asynchronous. You can read more about this breaking change in the [upgrade guide](/docs/app/guides/upgrading/version-15).
##### `next-async-request-api`
```bash filename="Terminal"
npx @next/codemod@latest next-async-request-api .
```
This codemod will transform dynamic APIs (`cookies()`, `headers()` and `draftMode()` from `next/headers`) that are now asynchronous to be properly awaited or wrapped with `React.use()` if applicable.
When an automatic migration isn't possible, the codemod will either add a typecast (if a TypeScript file) or a comment to inform the user that it needs to be manually reviewed & updated.
For example:
```tsx
import { cookies, headers } from 'next/headers'
const token = cookies().get('token')
function useToken() {
const token = cookies().get('token')
return token
}
export default function Page() {
const name = cookies().get('name')
}
function getHeader() {
return headers().get('x-foo')
}
```
Transforms into:
```tsx
import { use } from 'react'
import {
cookies,
headers,
type UnsafeUnwrappedCookies,
type UnsafeUnwrappedHeaders,
} from 'next/headers'
const token = (cookies() as unknown as UnsafeUnwrappedCookies).get('token')
function useToken() {
const token = use(cookies()).get('token')
return token
}
export default async function Page() {
const name = (await cookies()).get('name')
}
function getHeader() {
return (headers() as unknown as UnsafeUnwrappedHeaders).get('x-foo')
}
```
When we detect property access on the `params` or `searchParams` props in the page / route entries (`page.js`, `layout.js`, `route.js`, or `default.js`) or the `generateMetadata` / `generateViewport` APIs,
it will attempt to transform the callsite from a sync to an async function, and await the property access. If it can't be made async (such as with a Client Component), it will use `React.use` to unwrap the promise .
For example:
```tsx
// page.tsx
export default function Page({
params,
searchParams,
}: {
params: { slug: string }
searchParams: { [key: string]: string | string[] | undefined }
}) {
const { value } = searchParams
if (value === 'foo') {
// ...
}
}
export function generateMetadata({ params }: { params: { slug: string } }) {
const { slug } = params
return {
title: `My Page - ${slug}`,
}
}
```
Transforms into:
```tsx
// page.tsx
export default async function Page(props: {
params: Promise<{ slug: string }>
searchParams: Promise<{ [key: string]: string | string[] | undefined }>
}) {
const searchParams = await props.searchParams
const { value } = searchParams
if (value === 'foo') {
// ...
}
}
export async function generateMetadata(props: {
params: Promise<{ slug: string }>
}) {
const params = await props.params
const { slug } = params
return {
title: `My Page - ${slug}`,
}
}
```
> **Good to know:** When this codemod identifies a spot that might require manual intervention, but we aren't able to determine the exact fix, it will add a comment or typecast to the code to inform the user that it needs to be manually updated. These comments are prefixed with **@next/codemod**, and typecasts are prefixed with `UnsafeUnwrapped`.
> Your build will error until these comments are explicitly removed. [Read more](/docs/messages/sync-dynamic-apis).
#### Replace `geo` and `ip` properties of `NextRequest` with `@vercel/functions`
##### `next-request-geo-ip`
```bash filename="Terminal"
npx @next/codemod@latest next-request-geo-ip .
```
This codemod installs `@vercel/functions` and transforms `geo` and `ip` properties of `NextRequest` with corresponding `@vercel/functions` features.
For example:
```ts
import type { NextRequest } from 'next/server'
export function GET(req: NextRequest) {
const { geo, ip } = req
}
```
Transforms into:
```ts
import type { NextRequest } from 'next/server'
import { geolocation, ipAddress } from '@vercel/functions'
export function GET(req: NextRequest) {
const geo = geolocation(req)
const ip = ipAddress(req)
}
```
### 14.0
#### Migrate `ImageResponse` imports
##### `next-og-import`
```bash filename="Terminal"
npx @next/codemod@latest next-og-import .
```
This codemod moves transforms imports from `next/server` to `next/og` for usage of [Dynamic OG Image Generation](/docs/app/getting-started/metadata-and-og-images#generated-open-graph-images).
For example:
```js
import { ImageResponse } from 'next/server'
```
Transforms into:
```js
import { ImageResponse } from 'next/og'
```
#### Use `viewport` export
##### `metadata-to-viewport-export`
```bash filename="Terminal"
npx @next/codemod@latest metadata-to-viewport-export .
```
This codemod migrates certain viewport metadata to `viewport` export.
For example:
```js
export const metadata = {
title: 'My App',
themeColor: 'dark',
viewport: {
width: 1,
},
}
```
Transforms into:
```js
export const metadata = {
title: 'My App',
}
export const viewport = {
width: 1,
themeColor: 'dark',
}
```
### 13.2
#### Use Built-in Font
##### `built-in-next-font`
```bash filename="Terminal"
npx @next/codemod@latest built-in-next-font .
```
This codemod uninstalls the `@next/font` package and transforms `@next/font` imports into the built-in `next/font`.
For example:
```js
import { Inter } from '@next/font/google'
```
Transforms into:
```js
import { Inter } from 'next/font/google'
```
### 13.0
#### Rename Next Image Imports
##### `next-image-to-legacy-image`
```bash filename="Terminal"
npx @next/codemod@latest next-image-to-legacy-image .
```
Safely renames `next/image` imports in existing Next.js 10, 11, or 12 applications to `next/legacy/image` in Next.js 13. Also renames `next/future/image` to `next/image`.
For example:
```jsx filename="pages/index.js"
import Image1 from 'next/image'
import Image2 from 'next/future/image'
export default function Home() {
return (
<div>
<Image1 src="/test.jpg" width="200" height="300" />
<Image2 src="/test.png" width="500" height="400" />
</div>
)
}
```
Transforms into:
```jsx filename="pages/index.js"
// 'next/image' becomes 'next/legacy/image'
import Image1 from 'next/legacy/image'
// 'next/future/image' becomes 'next/image'
import Image2 from 'next/image'
export default function Home() {
return (
<div>
<Image1 src="/test.jpg" width="200" height="300" />
<Image2 src="/test.png" width="500" height="400" />
</div>
)
}
```
#### Migrate to the New Image Component
##### `next-image-experimental`
```bash filename="Terminal"
npx @next/codemod@latest next-image-experimental .
```
Dangerously migrates from `next/legacy/image` to the new `next/image` by adding inline styles and removing unused props.
- Removes `layout` prop and adds `style`.
- Removes `objectFit` prop and adds `style`.
- Removes `objectPosition` prop and adds `style`.
- Removes `lazyBoundary` prop.
- Removes `lazyRoot` prop.
#### Remove `<a>` Tags From Link Components
##### `new-link`
```bash filename="Terminal"
npx @next/codemod@latest new-link .
```
<AppOnly>
Remove `<a>` tags inside [Link Components](/docs/app/api-reference/components/link).
</AppOnly>
<PagesOnly>
Remove `<a>` tags inside [Link Components](/docs/pages/api-reference/components/link).
</PagesOnly>
For example:
```jsx
<Link href="/about">
<a>About</a>
</Link>
// transforms into
<Link href="/about">
About
</Link>
<Link href="/about">
<a onClick={() => console.log('clicked')}>About</a>
</Link>
// transforms into
<Link href="/about" onClick={() => console.log('clicked')}>
About
</Link>
```
### 11
#### Migrate from CRA
##### `cra-to-next`
```bash filename="Terminal"
npx @next/codemod cra-to-next
```
Migrates a Create React App project to Next.js; creating a Pages Router and necessary config to match behavior. Client-side only rendering is leveraged initially to prevent breaking compatibility due to `window` usage during SSR and can be enabled seamlessly to allow the gradual adoption of Next.js specific features.
Please share any feedback related to this transform [in this discussion](https://github.com/vercel/next.js/discussions/25858).
### 10
#### Add React imports
##### `add-missing-react-import`
```bash filename="Terminal"
npx @next/codemod add-missing-react-import
```
Transforms files that do not import `React` to include the import in order for the new [React JSX transform](https://reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html) to work.
For example:
```jsx filename="my-component.js"
export default class Home extends React.Component {
render() {
return <div>Hello World</div>
}
}
```
Transforms into:
```jsx filename="my-component.js"
import React from 'react'
export default class Home extends React.Component {
render() {
return <div>Hello World</div>
}
}
```
### 9
#### Transform Anonymous Components into Named Components
##### `name-default-component`
```bash filename="Terminal"
npx @next/codemod name-default-component
```
**Versions 9 and above.**
Transforms anonymous components into named components to make sure they work with [Fast Refresh](https://nextjs.org/blog/next-9-4#fast-refresh).
For example:
```jsx filename="my-component.js"
export default function () {
return <div>Hello World</div>
}
```
Transforms into:
```jsx filename="my-component.js"
export default function MyComponent() {
return <div>Hello World</div>
}
```
The component will have a camel-cased name based on the name of the file, and it also works with arrow functions.
### 8
> **Note**: Built-in AMP support and this codemod have been removed in Next.js 16.
#### Transform AMP HOC into page config
##### `withamp-to-config`
```bash filename="Terminal"
npx @next/codemod withamp-to-config
```
Transforms the `withAmp` HOC into Next.js 9 page configuration.
For example:
```js
// Before
import { withAmp } from 'next/amp'
function Home() {
return <h1>My AMP Page</h1>
}
export default withAmp(Home)
```
```js
// After
export default function Home() {
return <h1>My AMP Page</h1>
}
export const config = {
amp: true,
}
```
### 6
#### Use `withRouter`
##### `url-to-withrouter`
```bash filename="Terminal"
npx @next/codemod url-to-withrouter
```
Transforms the deprecated automatically injected `url` property on top level pages to using `withRouter` and the `router` property it injects. Read more here: [https://nextjs.org/docs/messages/url-deprecated](/docs/messages/url-deprecated)
For example:
```js filename="From"
import React from 'react'
export default class extends React.Component {
render() {
const { pathname } = this.props.url
return <div>Current pathname: {pathname}</div>
}
}
```
```js filename="To"
import React from 'react'
import { withRouter } from 'next/router'
export default withRouter(
class extends React.Component {
render() {
const { pathname } = this.props.router
return <div>Current pathname: {pathname}</div>
}
}
)
```
This is one case. All the cases that are transformed (and tested) can be found in the [`__testfixtures__` directory](https://github.com/vercel/next.js/tree/canary/packages/next-codemod/transforms/__testfixtures__/url-to-withrouter).
+7
View File
@@ -0,0 +1,7 @@
---
title: Upgrade Guides
nav_title: Upgrading
description: Learn how to upgrade to the latest versions of Next.js.
---
Learn how to upgrade to the latest versions of Next.js following the versions-specific guides:
+37
View File
@@ -0,0 +1,37 @@
---
title: How to upgrade to version 14
nav_title: Version 14
description: Upgrade your Next.js Application from Version 13 to 14.
---
{/* The content of this doc is shared between the app and pages router. You can use the `<PagesOnly>Content</PagesOnly>` component to add content that is specific to the Pages Router. Any shared content should not be wrapped in a component. */}
## Upgrading from 13 to 14
To update to Next.js version 14, run the following command using your preferred package manager:
```bash filename="Terminal"
npm i next@next-14 react@18 react-dom@18 && npm i eslint-config-next@next-14 -D
```
```bash filename="Terminal"
yarn add next@next-14 react@18 react-dom@18 && yarn add eslint-config-next@next-14 -D
```
```bash filename="Terminal"
pnpm i next@next-14 react@18 react-dom@18 && pnpm i eslint-config-next@next-14 -D
```
```bash filename="Terminal"
bun add next@next-14 react@18 react-dom@18 && bun add eslint-config-next@next-14 -D
```
> **Good to know:** If you are using TypeScript, ensure you also upgrade `@types/react` and `@types/react-dom` to their latest versions.
### v14 Summary
- The minimum Node.js version has been bumped from 16.14 to 18.17, since 16.x has reached end-of-life.
- The `next export` command has been removed in favor of `output: 'export'` config. Please see the [docs](https://nextjs.org/docs/app/guides/static-exports) for more information.
- The `next/server` import for `ImageResponse` was renamed to `next/og`. A [codemod is available](/docs/app/guides/upgrading/codemods#next-og-import) to safely and automatically rename your imports.
- The `@next/font` package has been fully removed in favor of the built-in `next/font`. A [codemod is available](/docs/app/guides/upgrading/codemods#built-in-next-font) to safely and automatically rename your imports.
- The WASM target for `next-swc` has been removed.
+627
View File
@@ -0,0 +1,627 @@
---
title: How to upgrade to version 15
nav_title: Version 15
description: Upgrade your Next.js Application from Version 14 to 15.
---
{/* The content of this doc is shared between the app and pages router. You can use the `<PagesOnly>Content</PagesOnly>` component to add content that is specific to the Pages Router. Any shared content should not be wrapped in a component. */}
## Upgrading from 14 to 15
To update to Next.js version 15, you can use the `upgrade` codemod:
```bash package="pnpm"
pnpm dlx @next/codemod@canary upgrade latest
```
```bash package="npm"
npx @next/codemod@canary upgrade latest
```
```bash package="yarn"
yarn dlx @next/codemod@canary upgrade latest
```
```bash package="bun"
bunx @next/codemod@canary upgrade latest
```
If you prefer to do it manually, ensure that you're installing the latest Next & React versions:
```bash package="pnpm"
pnpm add next@latest react@latest react-dom@latest eslint-config-next@latest
```
```bash package="npm"
npm install next@latest react@latest react-dom@latest eslint-config-next@latest
```
```bash package="yarn"
yarn add next@latest react@latest react-dom@latest eslint-config-next@latest
```
```bash package="bun"
bun add next@latest react@latest react-dom@latest eslint-config-next@latest
```
> **Good to know:**
>
> - If you see a peer dependencies warning, you may need to update `react` and `react-dom` to the suggested versions, or use the `--force` or `--legacy-peer-deps` flag to ignore the warning. This won't be necessary once both Next.js 15 and React 19 are stable.
## React 19
- The minimum versions of `react` and `react-dom` is now 19.
- `useFormState` has been replaced by `useActionState`. The `useFormState` hook is still available in React 19, but it is deprecated and will be removed in a future release. `useActionState` is recommended and includes additional properties like reading the `pending` state directly. [Learn more](https://react.dev/reference/react/useActionState).
- `useFormStatus` now includes additional keys like `data`, `method`, and `action`. If you are not using React 19, only the `pending` key is available. [Learn more](https://react.dev/reference/react-dom/hooks/useFormStatus).
- Read more in the [React 19 upgrade guide](https://react.dev/blog/2024/04/25/react-19-upgrade-guide).
> **Good to know:** If you are using TypeScript, ensure you also upgrade `@types/react` and `@types/react-dom` to their latest versions.
## Async Request APIs (Breaking change)
Previously synchronous Request-time APIs that rely on request information are now **asynchronous**:
- [`cookies`](/docs/app/api-reference/functions/cookies)
- [`headers`](/docs/app/api-reference/functions/headers)
- [`draftMode`](/docs/app/api-reference/functions/draft-mode)
- `params` in [`layout.js`](/docs/app/api-reference/file-conventions/layout), [`page.js`](/docs/app/api-reference/file-conventions/page), [`route.js`](/docs/app/api-reference/file-conventions/route), [`default.js`](/docs/app/api-reference/file-conventions/default), [`opengraph-image`](/docs/app/api-reference/file-conventions/metadata/opengraph-image), [`twitter-image`](/docs/app/api-reference/file-conventions/metadata/opengraph-image), [`icon`](/docs/app/api-reference/file-conventions/metadata/app-icons), and [`apple-icon`](/docs/app/api-reference/file-conventions/metadata/app-icons).
- `searchParams` in [`page.js`](/docs/app/api-reference/file-conventions/page)
To ease the burden of migration, a [codemod is available](/docs/app/guides/upgrading/codemods#150) to automate the process and the APIs can temporarily be accessed synchronously.
### `cookies`
#### Recommended Async Usage
```tsx
import { cookies } from 'next/headers'
// Before
const cookieStore = cookies()
const token = cookieStore.get('token')
// After
const cookieStore = await cookies()
const token = cookieStore.get('token')
```
#### Temporary Synchronous Usage
```tsx filename="app/page.tsx" switcher
import { cookies, type UnsafeUnwrappedCookies } from 'next/headers'
// Before
const cookieStore = cookies()
const token = cookieStore.get('token')
// After
const cookieStore = cookies() as unknown as UnsafeUnwrappedCookies
// will log a warning in dev
const token = cookieStore.get('token')
```
```jsx filename="app/page.js" switcher
import { cookies } from 'next/headers'
// Before
const cookieStore = cookies()
const token = cookieStore.get('token')
// After
const cookieStore = cookies()
// will log a warning in dev
const token = cookieStore.get('token')
```
### `headers`
#### Recommended Async Usage
```tsx
import { headers } from 'next/headers'
// Before
const headersList = headers()
const userAgent = headersList.get('user-agent')
// After
const headersList = await headers()
const userAgent = headersList.get('user-agent')
```
#### Temporary Synchronous Usage
```tsx filename="app/page.tsx" switcher
import { headers, type UnsafeUnwrappedHeaders } from 'next/headers'
// Before
const headersList = headers()
const userAgent = headersList.get('user-agent')
// After
const headersList = headers() as unknown as UnsafeUnwrappedHeaders
// will log a warning in dev
const userAgent = headersList.get('user-agent')
```
```jsx filename="app/page.js" switcher
import { headers } from 'next/headers'
// Before
const headersList = headers()
const userAgent = headersList.get('user-agent')
// After
const headersList = headers()
// will log a warning in dev
const userAgent = headersList.get('user-agent')
```
### `draftMode`
#### Recommended Async Usage
```tsx
import { draftMode } from 'next/headers'
// Before
const { isEnabled } = draftMode()
// After
const { isEnabled } = await draftMode()
```
#### Temporary Synchronous Usage
```tsx filename="app/page.tsx" switcher
import { draftMode, type UnsafeUnwrappedDraftMode } from 'next/headers'
// Before
const { isEnabled } = draftMode()
// After
// will log a warning in dev
const { isEnabled } = draftMode() as unknown as UnsafeUnwrappedDraftMode
```
```jsx filename="app/page.js" switcher
import { draftMode } from 'next/headers'
// Before
const { isEnabled } = draftMode()
// After
// will log a warning in dev
const { isEnabled } = draftMode()
```
### `params` & `searchParams`
#### Asynchronous Layout
```tsx filename="app/layout.tsx" switcher
// Before
type Params = { slug: string }
export function generateMetadata({ params }: { params: Params }) {
const { slug } = params
}
export default async function Layout({
children,
params,
}: {
children: React.ReactNode
params: Params
}) {
const { slug } = params
}
// After
type Params = Promise<{ slug: string }>
export async function generateMetadata({ params }: { params: Params }) {
const { slug } = await params
}
export default async function Layout({
children,
params,
}: {
children: React.ReactNode
params: Params
}) {
const { slug } = await params
}
```
```jsx filename="app/layout.js" switcher
// Before
export function generateMetadata({ params }) {
const { slug } = params
}
export default async function Layout({ children, params }) {
const { slug } = params
}
// After
export async function generateMetadata({ params }) {
const { slug } = await params
}
export default async function Layout({ children, params }) {
const { slug } = await params
}
```
#### Synchronous Layout
```tsx filename="app/layout.tsx" switcher
// Before
type Params = { slug: string }
export default function Layout({
children,
params,
}: {
children: React.ReactNode
params: Params
}) {
const { slug } = params
}
// After
import { use } from 'react'
type Params = Promise<{ slug: string }>
export default function Layout(props: {
children: React.ReactNode
params: Params
}) {
const params = use(props.params)
const slug = params.slug
}
```
```jsx filename="app/layout.js" switcher
// Before
export default function Layout({ children, params }) {
const { slug } = params
}
// After
import { use } from 'react'
export default async function Layout(props) {
const params = use(props.params)
const slug = params.slug
}
```
#### Asynchronous Page
```tsx filename="app/page.tsx" switcher
// Before
type Params = { slug: string }
type SearchParams = { [key: string]: string | string[] | undefined }
export function generateMetadata({
params,
searchParams,
}: {
params: Params
searchParams: SearchParams
}) {
const { slug } = params
const { query } = searchParams
}
export default async function Page({
params,
searchParams,
}: {
params: Params
searchParams: SearchParams
}) {
const { slug } = params
const { query } = searchParams
}
// After
type Params = Promise<{ slug: string }>
type SearchParams = Promise<{ [key: string]: string | string[] | undefined }>
export async function generateMetadata(props: {
params: Params
searchParams: SearchParams
}) {
const params = await props.params
const searchParams = await props.searchParams
const slug = params.slug
const query = searchParams.query
}
export default async function Page(props: {
params: Params
searchParams: SearchParams
}) {
const params = await props.params
const searchParams = await props.searchParams
const slug = params.slug
const query = searchParams.query
}
```
```jsx filename="app/page.js" switcher
// Before
export function generateMetadata({ params, searchParams }) {
const { slug } = params
const { query } = searchParams
}
export default function Page({ params, searchParams }) {
const { slug } = params
const { query } = searchParams
}
// After
export async function generateMetadata(props) {
const params = await props.params
const searchParams = await props.searchParams
const slug = params.slug
const query = searchParams.query
}
export async function Page(props) {
const params = await props.params
const searchParams = await props.searchParams
const slug = params.slug
const query = searchParams.query
}
```
#### Synchronous Page
```tsx
'use client'
// Before
type Params = { slug: string }
type SearchParams = { [key: string]: string | string[] | undefined }
export default function Page({
params,
searchParams,
}: {
params: Params
searchParams: SearchParams
}) {
const { slug } = params
const { query } = searchParams
}
// After
import { use } from 'react'
type Params = Promise<{ slug: string }>
type SearchParams = Promise<{ [key: string]: string | string[] | undefined }>
export default function Page(props: {
params: Params
searchParams: SearchParams
}) {
const params = use(props.params)
const searchParams = use(props.searchParams)
const slug = params.slug
const query = searchParams.query
}
```
```jsx
// Before
export default function Page({ params, searchParams }) {
const { slug } = params
const { query } = searchParams
}
// After
import { use } from "react"
export default function Page(props) {
const params = use(props.params)
const searchParams = use(props.searchParams)
const slug = params.slug
const query = searchParams.query
}
```
#### Route Handlers
```tsx filename="app/api/route.ts" switcher
// Before
type Params = { slug: string }
export async function GET(request: Request, segmentData: { params: Params }) {
const params = segmentData.params
const slug = params.slug
}
// After
type Params = Promise<{ slug: string }>
export async function GET(request: Request, segmentData: { params: Params }) {
const params = await segmentData.params
const slug = params.slug
}
```
```js filename="app/api/route.js" switcher
// Before
export async function GET(request, segmentData) {
const params = segmentData.params
const slug = params.slug
}
// After
export async function GET(request, segmentData) {
const params = await segmentData.params
const slug = params.slug
}
```
<AppOnly>
## `runtime` configuration (Breaking change)
The `runtime` [segment configuration](/docs/app/api-reference/file-conventions/route-segment-config/runtime) previously supported a value of `experimental-edge` in addition to `edge`. Both configurations refer to the same thing, and to simplify the options, we will now error if `experimental-edge` is used. To fix this, update your `runtime` configuration to `edge`. A [codemod](/docs/app/guides/upgrading/codemods#app-dir-runtime-config-experimental-edge) is available to automatically do this.
</AppOnly>
## `fetch` requests
[`fetch` requests](/docs/app/api-reference/functions/fetch) are no longer cached by default.
To opt specific `fetch` requests into caching, you can pass the `cache: 'force-cache'` option.
```js filename="app/layout.js"
export default async function RootLayout() {
const a = await fetch('https://...') // Not Cached
const b = await fetch('https://...', { cache: 'force-cache' }) // Cached
// ...
}
```
To opt all `fetch` requests in a layout or page into caching, you can use the `export const fetchCache = 'default-cache'` [segment config option](/docs/app/api-reference/file-conventions/route-segment-config). If individual `fetch` requests specify a `cache` option, that will be used instead.
```js filename="app/layout.js"
// Since this is the root layout, all fetch requests in the app
// that don't set their own cache option will be cached.
export const fetchCache = 'default-cache'
export default async function RootLayout() {
const a = await fetch('https://...') // Cached
const b = await fetch('https://...', { cache: 'no-store' }) // Not cached
// ...
}
```
## Route Handlers
`GET` functions in [Route Handlers](/docs/app/api-reference/file-conventions/route) are no longer cached by default. To opt `GET` methods into caching, you can use a [route config option](/docs/app/api-reference/file-conventions/route-segment-config) such as `export const dynamic = 'force-static'` in your Route Handler file.
```js filename="app/api/route.js"
export const dynamic = 'force-static'
export async function GET() {}
```
## Client Cache
When navigating between pages via `<Link>` or `useRouter`, [page](/docs/app/api-reference/file-conventions/page) segments are no longer reused from the [Client Cache](/docs/app/glossary#client-cache). However, they are still reused during browser backward and forward navigation and for shared layouts.
To opt page segments into caching, you can use the [`staleTimes`](/docs/app/api-reference/config/next-config-js/staleTimes) config option:
```js filename="next.config.js"
/** @type {import('next').NextConfig} */
const nextConfig = {
experimental: {
staleTimes: {
dynamic: 30,
static: 180,
},
},
}
module.exports = nextConfig
```
[Layouts](/docs/app/api-reference/file-conventions/layout) and [loading states](/docs/app/api-reference/file-conventions/loading) are still cached and reused on navigation.
## `next/font`
The `@next/font` package has been removed in favor of the built-in [`next/font`](/docs/app/api-reference/components/font). A [codemod is available](/docs/app/guides/upgrading/codemods#built-in-next-font) to safely and automatically rename your imports.
```js filename="app/layout.js"
// Before
import { Inter } from '@next/font/google'
// After
import { Inter } from 'next/font/google'
```
## bundlePagesRouterDependencies
`experimental.bundlePagesExternals` is now stable and renamed to `bundlePagesRouterDependencies`.
```js filename="next.config.js"
/** @type {import('next').NextConfig} */
const nextConfig = {
// Before
experimental: {
bundlePagesExternals: true,
},
// After
bundlePagesRouterDependencies: true,
}
module.exports = nextConfig
```
## serverExternalPackages
`experimental.serverComponentsExternalPackages` is now stable and renamed to `serverExternalPackages`.
```js filename="next.config.js"
/** @type {import('next').NextConfig} */
const nextConfig = {
// Before
experimental: {
serverComponentsExternalPackages: ['package-name'],
},
// After
serverExternalPackages: ['package-name'],
}
module.exports = nextConfig
```
## Speed Insights
Auto instrumentation for Speed Insights was removed in Next.js 15.
To continue using Speed Insights, follow the [Vercel Speed Insights Quickstart](https://vercel.com/docs/speed-insights/quickstart) guide.
## `NextRequest` Geolocation
The `geo` and `ip` properties on `NextRequest` have been removed as these values are provided by your hosting provider. A [codemod](/docs/app/guides/upgrading/codemods#150) is available to automate this migration.
If you are using Vercel, you can alternatively use the `geolocation` and `ipAddress` functions from [`@vercel/functions`](https://vercel.com/docs/functions/vercel-functions-package) instead:
```ts filename="middleware.ts"
import { geolocation } from '@vercel/functions'
import type { NextRequest } from 'next/server'
export function middleware(request: NextRequest) {
const { city } = geolocation(request)
// ...
}
```
```ts filename="middleware.ts"
import { ipAddress } from '@vercel/functions'
import type { NextRequest } from 'next/server'
export function middleware(request: NextRequest) {
const ip = ipAddress(request)
// ...
}
```
File diff suppressed because it is too large Load Diff