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. |