AvatarJuan VictorAboutStackProjectsBlogsInspiring Insights
Download CV
Home
About
Stack
Projects
Blogs
Inspiring Insights
Download CV
AvatarJuan Victor
AboutStackProjectsBlogsInspiring Insights

© 2025 JV Portfolio. All rights reserved.

Updated: November 17, 2024

🔥Asynchronous Request APIs in Next.js 15: A Major Shift (Chapter 1)

🚀 Introduction

Next.js 15 introduces a breaking change by transitioning several request-specific APIs to asynchronous operations. This shift enhances performance and lays the groundwork for future optimizations. The affected APIs include cookies(), headers(), draftMode(), and route-specific parameters such as params and searchParams. This article covers these changes in detail and provides updated code examples to help developers migrate seamlessly.

🤔 Why the Change?

The transition to asynchronous request APIs allows the Next.js server to prepare responses more efficiently before requests arrive, improving overall performance. It also aligns with modern best practices for handling I/O-heavy operations, such as database queries, authentication checks, and dynamic content generation.

⚡Affected APIs and Code Examples

🍪 cookies() API (Now Asynchronous)

The cookies() API, used for managing cookies in Next.js, is now asynchronous.

✅ Example: Fetching Cookies Asynchronously

🔹Key Changes:

  • cookies() must now be awaited.
  • This ensures cookies are fetched efficiently before processing continues.

📩 headers() API (Now Asynchronous)

The headers() API, previously synchronous, must now be awaited.

✅ Example: Retrieving Request Headers

🔹Key Changes:

  • headers() now returns a promise, requiring await.
  • This change ensures the API can be optimized internally.

📝 draftMode() API (Now Asynchronous)

The draftMode() API for previewing draft content must also be awaited.

✅ Example: Checking Draft Mode

🔹Key Changes:

  • draftMode() requires await to retrieve draft state.
  • Useful for managing preview functionality efficiently.

🔀 params in Route Handlers (Now Asynchronous)

In Next.js 15, params in layout.js, page.js, route.js, default.js, generateMetadata, and generateViewport are now asynchronous.

✅ Example: Using params Asynchronously

🔹Key Changes:

  • params must now be awaited when used in relevant files.
  • Helps optimize how route parameters are accessed.

🔎 params & searchParams (Now Asynchronous)

params and searchParams are API's that have transitioned to asynchronous behavior.

✅ Example: Asynchronous Layout & Page

✅ Example: Synchronous Layout & Page

🔹Key Changes:

  • params and searchParams must now be awaited.
  • Ensures query parameters are properly processed before rendering.

🔧 Migration Guide

To assist with the transition, Next.js provides an automated codemod to refactor your code:

This tool updates affected API calls to their new asynchronous versions automatically. However, developers should manually review changes for edge cases.

🎯 Conclusion

The shift to asynchronous request APIs in Next.js 15 significantly improves efficiency, especially for applications relying on headers, cookies, and dynamic route parameters. Developers should update their projects accordingly and leverage the provided codemod for a smoother migration. By adopting these changes, Next.js applications will be better optimized for modern web performance needs.

📌 References

  • 📖 Release Next.js 15

  • 📖 Async Request APIs (Breaking change)

1
// app/page.tsx
2
import { cookies } from 'next/headers';
3
4
export async function AdminPanel() {
5
const cookieStore = await cookies(); // Await is now required
6
const token = cookieStore.get('token');
7
8
return token ? 'Authenticated' : 'Not Authenticated';
9
}
10
1
import { headers } from 'next/headers'
2
3
// 🟡 Before
4
const headersList = headers()
5
const userAgent = headersList.get('user-agent')
6
7
// ✅ After
8
const headersList = await headers()
9
const userAgent = headersList.get('user-agent')
10
1
import { draftMode } from 'next/headers'
2
3
// 🟡 Before
4
const { isEnabled } = draftMode()
5
6
// ✅ After
7
const { isEnabled } = await draftMode()
8
}
9
1
// app/api/route.ts
2
3
// 🟡 Before
4
type Params = { slug: string }
5
6
export async function GET(request: Request, segmentData: { params: Params }) {
7
const params = segmentData.params
8
const slug = params.slug
9
}
10
11
// ✅ After
12
type Params = Promise<{ slug: string }>
13
14
export async function GET(request: Request, segmentData: { params: Params }) {
15
const params = await segmentData.params
16
const slug = params.slug
17
}
18
1
// app/layout.tsx
2
3
type Params = Promise<{ slug: string }>
4
5
export async function generateMetadata({ params }: { params: Params }) {
6
const { slug } = await params
7
}
8
9
export default async function Layout({
10
children,
11
params,
12
}: {
13
children: React.ReactNode
14
params: Params
15
}) {
16
const { slug } = await params
17
}
18
19
20
// app/page.tsx
21
22
type Params = Promise<{ slug: string }>
23
type SearchParams = Promise<{ [key: string]: string | string[] | undefined }>
24
25
export async function generateMetadata(props: {
26
params: Params
27
searchParams: SearchParams
28
}) {
29
const params = await props.params
30
const searchParams = await props.searchParams
31
const slug = params.slug
32
const query = searchParams.query
33
}
34
35
export default async function Page(props: {
36
params: Params
37
searchParams: SearchParams
38
}) {
39
const params = await props.params
40
const searchParams = await props.searchParams
41
const slug = params.slug
42
const query = searchParams.query
43
}
44
1
// app/layout.tsx
2
3
import { use } from 'react'
4
5
type Params = Promise<{ slug: string }>
6
7
export default function Layout(props: {
8
children: React.ReactNode
9
params: Params
10
}) {
11
const params = use(props.params)
12
const slug = params.slug
13
}
14
15
16
// app/page.tsx
17
18
import { use } from 'react'
19
20
type Params = Promise<{ slug: string }>
21
type SearchParams = Promise<{ [key: string]: string | string[] | undefined }>
22
23
export default function Page(props: {
24
params: Params
25
searchParams: SearchParams
26
}) {
27
const params = use(props.params)
28
const searchParams = use(props.searchParams)
29
const slug = params.slug
30
const query = searchParams.query
31
}
32
1
2
npx @next/codemod@canary next-async-request-api
3