From 46fed94ab58dd78e196255c4462b97610b59bab9 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Wed, 11 Feb 2026 15:17:03 +0000
Subject: [PATCH 1/4] docs: clarify request API usage in after() for pages vs
route handlers
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Restructure the 'With request APIs' section of the after() docs to clearly
differentiate between:
- Route Handlers & Server Functions: where cookies/headers CAN be called
directly inside the after() callback
- Server Components (pages/layouts): where cookies/headers CANNOT be used
inside after() and must be read beforehand
Add a new code example showing the correct pattern for Server Components
(read request data before after() and pass the values in).
Also fix incorrect await syntax in the route handler example:
- Before: (await headers().get(...)) — awaits the result of .get()
- After: (await headers()).get(...) — correctly awaits the headers() promise
Co-authored-by: Jimmy Lai
---
.../03-api-reference/04-functions/after.mdx | 68 ++++++++++++++++---
1 file changed, 60 insertions(+), 8 deletions(-)
diff --git a/docs/01-app/03-api-reference/04-functions/after.mdx b/docs/01-app/03-api-reference/04-functions/after.mdx
index 3a7d179358d6..9d639640aed9 100644
--- a/docs/01-app/03-api-reference/04-functions/after.mdx
+++ b/docs/01-app/03-api-reference/04-functions/after.mdx
@@ -59,9 +59,13 @@ export default function Layout({ children }) {
### With request APIs
-You can use request APIs such as [`cookies`](/docs/app/api-reference/functions/cookies) and [`headers`](/docs/app/api-reference/functions/headers) inside `after` in [Server Functions](/docs/app/getting-started/updating-data) and [Route Handlers](/docs/app/api-reference/file-conventions/route). This is useful for logging activity after a mutation. For example:
+Whether you can use request APIs like [`cookies`](/docs/app/api-reference/functions/cookies) and [`headers`](/docs/app/api-reference/functions/headers) inside `after` depends on where `after` is called from.
-```ts filename="app/api/route.ts" highlight={2,7-9} switcher
+#### In Route Handlers and Server Functions
+
+You can call `cookies` and `headers` directly inside the `after` callback when used in [Route Handlers](/docs/app/api-reference/file-conventions/route) and [Server Functions](/docs/app/getting-started/updating-data). This is useful for logging activity after a mutation or API request. For example:
+
+```ts filename="app/api/route.ts" highlight={2,10-13} switcher
import { after } from 'next/server'
import { cookies, headers } from 'next/headers'
import { logUserAction } from '@/app/utils'
@@ -72,9 +76,9 @@ export async function POST(request: Request) {
// Log user activity for analytics
after(async () => {
- const userAgent = (await headers().get('user-agent')) || 'unknown'
+ const userAgent = (await headers()).get('user-agent') || 'unknown'
const sessionCookie =
- (await cookies().get('session-id'))?.value || 'anonymous'
+ (await cookies()).get('session-id')?.value || 'anonymous'
logUserAction({ sessionCookie, userAgent })
})
@@ -86,7 +90,7 @@ export async function POST(request: Request) {
}
```
-```js filename="app/api/route.js" highlight={2,7-9} switcher
+```js filename="app/api/route.js" highlight={2,10-13} switcher
import { after } from 'next/server'
import { cookies, headers } from 'next/headers'
import { logUserAction } from '@/app/utils'
@@ -97,9 +101,9 @@ export async function POST(request) {
// Log user activity for analytics
after(async () => {
- const userAgent = (await headers().get('user-agent')) || 'unknown'
+ const userAgent = (await headers()).get('user-agent') || 'unknown'
const sessionCookie =
- (await cookies().get('session-id'))?.value || 'anonymous'
+ (await cookies()).get('session-id')?.value || 'anonymous'
logUserAction({ sessionCookie, userAgent })
})
@@ -111,7 +115,55 @@ export async function POST(request) {
}
```
-However, you cannot use these request APIs inside `after` in [Server Components](/docs/app/getting-started/server-and-client-components). This is because Next.js needs to know which part of the tree access the request APIs to support [Cache Components](/docs/app/getting-started/cache-components), but `after` runs after React's rendering lifecycle.
+#### In Server Components (pages and layouts)
+
+[Server Components](/docs/app/getting-started/server-and-client-components) (including pages, layouts, and `generateMetadata`) **cannot** use `cookies`, `headers`, or other [Dynamic APIs](/docs/app/guides/caching#dynamic-rendering) inside `after`. This is because Next.js needs to know which part of the component tree accesses request data to support [partial prerendering](/docs/app/getting-started/partial-prerendering) and [Cache Components](/docs/app/getting-started/cache-components), but `after` runs after React's rendering lifecycle.
+
+If you need request data inside an `after` callback in a Server Component, read it beforehand and pass the values in:
+
+```tsx filename="app/page.tsx" highlight={8-10,12} switcher
+import { after } from 'next/server'
+import { cookies, headers } from 'next/headers'
+import { logUserAction } from '@/app/utils'
+
+export default async function Page() {
+ // Read request data before `after` — this is allowed
+ // These calls will be read during the component's rendering lifecycle
+ const userAgent = (await headers()).get('user-agent') || 'unknown'
+ const sessionCookie =
+ (await cookies()).get('session-id')?.value || 'anonymous'
+
+ after(() => {
+ // Use the values read above
+ logUserAction({ sessionCookie, userAgent })
+ })
+
+ return My Page
+}
+```
+
+```jsx filename="app/page.jsx" highlight={8-10,12} switcher
+import { after } from 'next/server'
+import { cookies, headers } from 'next/headers'
+import { logUserAction } from '@/app/utils'
+
+export default async function Page() {
+ // Read request data before `after` — this is allowed
+ // These calls will be read during the component's rendering lifecycle
+ const userAgent = (await headers()).get('user-agent') || 'unknown'
+ const sessionCookie =
+ (await cookies()).get('session-id')?.value || 'anonymous'
+
+ after(() => {
+ // Use the values read above
+ logUserAction({ sessionCookie, userAgent })
+ })
+
+ return My Page
+}
+```
+
+Calling `cookies()` or `headers()` inside the `after` callback in a Server Component will throw a runtime error.
## Platform Support
From 2149168b307080a97b5b3776017d9f5afd4851aa Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Wed, 11 Feb 2026 15:21:02 +0000
Subject: [PATCH 2/4] fix: broken link to partial prerendering docs
Co-authored-by: Jimmy Lai
---
docs/01-app/03-api-reference/04-functions/after.mdx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/01-app/03-api-reference/04-functions/after.mdx b/docs/01-app/03-api-reference/04-functions/after.mdx
index 9d639640aed9..0b40f2e55a40 100644
--- a/docs/01-app/03-api-reference/04-functions/after.mdx
+++ b/docs/01-app/03-api-reference/04-functions/after.mdx
@@ -117,7 +117,7 @@ export async function POST(request) {
#### In Server Components (pages and layouts)
-[Server Components](/docs/app/getting-started/server-and-client-components) (including pages, layouts, and `generateMetadata`) **cannot** use `cookies`, `headers`, or other [Dynamic APIs](/docs/app/guides/caching#dynamic-rendering) inside `after`. This is because Next.js needs to know which part of the component tree accesses request data to support [partial prerendering](/docs/app/getting-started/partial-prerendering) and [Cache Components](/docs/app/getting-started/cache-components), but `after` runs after React's rendering lifecycle.
+[Server Components](/docs/app/getting-started/server-and-client-components) (including pages, layouts, and `generateMetadata`) **cannot** use `cookies`, `headers`, or other [Dynamic APIs](/docs/app/guides/caching#dynamic-rendering) inside `after`. This is because Next.js needs to know which part of the component tree accesses request data to support [Partial Prerendering](/docs/app/glossary#partial-prerendering-ppr) and [Cache Components](/docs/app/getting-started/cache-components), but `after` runs after React's rendering lifecycle.
If you need request data inside an `after` callback in a Server Component, read it beforehand and pass the values in:
From cf920558c2c2ecb5be06247bf6a33966ff00f55b Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Wed, 11 Feb 2026 15:35:02 +0000
Subject: [PATCH 3/4] docs: add Cache Components example for after() with
request APIs
Add a new 'With Cache Components' subsection showing the recommended
pattern for using after() alongside cookies/headers in pages that use
Partial Prerendering. The example demonstrates:
- Wrapping the dynamic component in so the page can prerender
- Reading cookies() in the dynamic component during render
- Passing the values into after() via closure
This addresses feedback requesting clearer examples for pages and
Cache Components pages.
Co-authored-by: Jimmy Lai
---
.../03-api-reference/04-functions/after.mdx | 68 +++++++++++++++++++
1 file changed, 68 insertions(+)
diff --git a/docs/01-app/03-api-reference/04-functions/after.mdx b/docs/01-app/03-api-reference/04-functions/after.mdx
index 0b40f2e55a40..c53466a17cca 100644
--- a/docs/01-app/03-api-reference/04-functions/after.mdx
+++ b/docs/01-app/03-api-reference/04-functions/after.mdx
@@ -165,6 +165,74 @@ export default async function Page() {
Calling `cookies()` or `headers()` inside the `after` callback in a Server Component will throw a runtime error.
+#### With Cache Components
+
+When using [Cache Components](/docs/app/getting-started/cache-components), components that access request data like `cookies` or `headers` must be wrapped in [``](https://react.dev/reference/react/Suspense) so the rest of the page can be prerendered into a static shell.
+
+You can combine this pattern with `after` by reading request data in a dynamic component and passing it into `after`:
+
+```tsx filename="app/page.tsx" highlight={18-19,22-24} switcher
+import { Suspense } from 'react'
+import { after } from 'next/server'
+import { cookies } from 'next/headers'
+import { logUserAction } from '@/app/utils'
+
+export default function Page() {
+ return (
+ <>
+ Part of the static shell
+ Loading...
}>
+
+
+ >
+ )
+}
+
+async function DynamicContent() {
+ const sessionCookie =
+ (await cookies()).get('session-id')?.value || 'anonymous'
+
+ // Schedule work after the response is sent
+ after(() => {
+ logUserAction({ sessionCookie })
+ })
+
+ return Your session: {sessionCookie}
+}
+```
+
+```jsx filename="app/page.jsx" highlight={18-19,22-24} switcher
+import { Suspense } from 'react'
+import { after } from 'next/server'
+import { cookies } from 'next/headers'
+import { logUserAction } from '@/app/utils'
+
+export default function Page() {
+ return (
+ <>
+ Part of the static shell
+ Loading...}>
+
+
+ >
+ )
+}
+
+async function DynamicContent() {
+ const sessionCookie =
+ (await cookies()).get('session-id')?.value || 'anonymous'
+
+ // Schedule work after the response is sent
+ after(() => {
+ logUserAction({ sessionCookie })
+ })
+
+ return Your session: {sessionCookie}
+}
+```
+
+In this example, `` and the `` fallback are included in the static shell. `DynamicContent` reads the cookie during rendering and passes it into `after` via closure. Since `cookies()` is called _outside_ the `after` callback (during the component's render), this works correctly.
+
## Platform Support
| Deployment Option | Supported |
From 064a900e8938da149e69b08430cb6ae7218a87d8 Mon Sep 17 00:00:00 2001
From: Joseph Chamochumbi
Date: Wed, 11 Feb 2026 20:50:56 +0100
Subject: [PATCH 4/4] docs: fix version history table header consistency
---
docs/01-app/03-api-reference/04-functions/after.mdx | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/docs/01-app/03-api-reference/04-functions/after.mdx b/docs/01-app/03-api-reference/04-functions/after.mdx
index c53466a17cca..6cd5485b14fe 100644
--- a/docs/01-app/03-api-reference/04-functions/after.mdx
+++ b/docs/01-app/03-api-reference/04-functions/after.mdx
@@ -297,7 +297,7 @@ const handler = (req, res) => {
## Version History
-| Version History | Description |
-| --------------- | ---------------------------- |
-| `v15.1.0` | `after` became stable. |
-| `v15.0.0-rc` | `unstable_after` introduced. |
+| Version | Changes |
+| ------------ | ---------------------------- |
+| `v15.1.0` | `after` became stable. |
+| `v15.0.0-rc` | `unstable_after` introduced. |