---
title: "Async Storage"
description: "Next.js uses asynchronous storage infrastructure built on AsyncLocalStorage to propagate request-scoped execution contexts, render metadata, and dynamic states across asynchronous boundaries. By ma..."
last_updated: "2026-10-12T06:38:56.881153+00:00"
canonical_url: "https://www.doc0.dev/docs/8f4009b0-65bd-4480-9b00-e201f0914bb3/technical/server-runtime/async-storage"
---

<details>
<summary>Relevant source files</summary>

The following files were used as context for generating this wiki page:

- [packages/next/src/server/app-render/after-task-async-storage-instance.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/after-task-async-storage-instance.ts)
- [packages/next/src/server/app-render/action-async-storage-instance.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/action-async-storage-instance.ts)
- [packages/next/src/server/async-storage/request-store.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/async-storage/request-store.ts)
- [packages/next/src/server/app-render/work-unit-async-storage.external.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/work-unit-async-storage.external.ts)
- [packages/next/src/server/app-render/console-async-storage-instance.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/console-async-storage-instance.ts)
- [packages/next/src/server/app-render/dynamic-access-async-storage-instance.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/dynamic-access-async-storage-instance.ts)
- [packages/next/src/server/app-render/work-async-storage.external.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/work-async-storage.external.ts)
- [packages/next/src/server/app-render/async-local-storage.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/async-local-storage.ts)
- [packages/next/src/server/request/cookies.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/request/cookies.ts)
- [packages/next/src/experimental/testmode/context.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/experimental/testmode/context.ts)
- [packages/next/src/server/app-render/work-async-storage-instance.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/work-async-storage-instance.ts)
- [packages/next/src/server/web/adapter.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/web/adapter.ts)
- [packages/next/src/server/base-server.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/base-server.ts)
- [packages/next/src/server/app-render/work-unit-async-storage-instance.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/work-unit-async-storage-instance.ts)
- [packages/next/src/server/async-storage/draft-mode-provider.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/async-storage/draft-mode-provider.ts)
- [packages/next/src/server/request/headers.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/request/headers.ts)
- [packages/next/src/server/next-server.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/next-server.ts)
- [packages/next/src/client/components/segment-cache/navigation-testing-lock.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/segment-cache/navigation-testing-lock.ts)
- [packages/next/src/server/lib/trace/request-insights-identity.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/lib/trace/request-insights-identity.ts)
- [packages/next/src/server/request/draft-mode.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/request/draft-mode.ts)
- [packages/next/src/server/app-render/action-async-storage.external.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/action-async-storage.external.ts)
- [packages/next/src/server/async-storage/with-store.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/async-storage/with-store.ts)
- [packages/next/src/server/after/builtin-request-context.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/after/builtin-request-context.ts)
- [packages/next/src/server/app-render/after-task-async-storage.external.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/after-task-async-storage.external.ts)
- [packages/next/src/server/app-render/console-async-storage.external.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/console-async-storage.external.ts)
- [packages/next/src/client/components/server-async-storage.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/server-async-storage.ts)
- [packages/next/src/server/app-render/dynamic-access-async-storage.external.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/dynamic-access-async-storage.external.ts)
- [packages/next/src/server/web/spec-extension/adapters/request-cookies.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/web/spec-extension/adapters/request-cookies.ts)
- [packages/next/src/server/async-storage/work-store.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/async-storage/work-store.ts)
- [packages/next/src/client/components/server-async-storage.browser.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/server-async-storage.browser.ts)
</details>

## Overview

Next.js uses asynchronous storage infrastructure built on `AsyncLocalStorage` to propagate request-scoped execution contexts, render metadata, and dynamic states across asynchronous boundaries. By maintaining realm-safe singletons via global symbols and fallback shims, the system tracks active rendering phases, request headers, cookies, and draft mode parameters across Node.js servers, worker threads, and the [Edge Runtime](https://www.doc0.dev/docs/8f4009b0-65bd-4480-9b00-e201f0914bb3/technical/server-runtime/edge-runtime). These storage contexts coordinate request lifecycles throughout [Server Architecture](https://www.doc0.dev/docs/8f4009b0-65bd-4480-9b00-e201f0914bb3/technical/server-runtime/server-architecture), managing dynamic data access enforcement and execution boundaries for [App Rendering](https://www.doc0.dev/docs/8f4009b0-65bd-4480-9b00-e201f0914bb3/technical/app-rendering/app-rendering) and [Route Handlers](https://www.doc0.dev/docs/8f4009b0-65bd-4480-9b00-e201f0914bb3/technical/server-runtime/route-handlers).

Sources: [packages/next/src/server/app-render/async-local-storage.ts:36-83](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/async-local-storage.ts#L36-L83), [packages/next/src/server/app-render/work-unit-async-storage.external.ts:28-34](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/work-unit-async-storage.external.ts#L28-L34), [packages/next/src/server/request/cookies.ts:36-147](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/request/cookies.ts#L36-L147)

## Global Storage Infrastructure

### Global AsyncLocalStorage Singletons

Next.js initializes and exports several core `AsyncLocalStorage` singletons to manage request contexts, action execution, console logging interception, dynamic access tracking, and background tasks. Each storage instance is created by calling `getOrCreateGlobalAsyncLocalStorage` with a unique identifier string combined with the current Next.js version (`process.env.__NEXT_VERSION`) via `Symbol.for`.

```typescript
export function getOrCreateGlobalAsyncLocalStorage<Store extends {}>(
  name: string
): AsyncLocalStorage<Store> {
  const key = Symbol.for(`@next/${name}@${process.env.__NEXT_VERSION}`)

  const globalStore = globalThis as typeof globalThis & {
    [key: symbol]: AsyncLocalStorage<Store> | undefined
  }

  return (globalStore[key] ??= createAsyncLocalStorage<Store>())
}
```
Sources: [packages/next/src/server/app-render/async-local-storage.ts:73-83](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/async-local-storage.ts#L73-L83)

| Singleton Instance Name | Storage Identifier String | Associated Type |
| :--- | :--- | :--- |
| `actionAsyncStorageInstance` | `'action-async-storage'` | `ActionAsyncStorage` |
| `afterTaskAsyncStorageInstance` | `'after-task-async-storage'` | `AfterTaskAsyncStorage` |
| `consoleAsyncStorageInstance` | `'console-async-storage'` | `ConsoleAsyncStorage` |
| `dynamicAccessAsyncStorageInstance` | `'dynamic-access-async-storage'` | `DynamicAccessStorage` |
| `workAsyncStorageInstance` | `'work-async-storage'` | `WorkAsyncStorage` |
| `workUnitAsyncStorageInstance` | `'work-unit-async-storage'` | `WorkUnitAsyncStorage` |

Sources: [packages/next/src/server/app-render/after-task-async-storage-instance.ts:4-5](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/after-task-async-storage-instance.ts#L4-L5), [packages/next/src/server/app-render/action-async-storage-instance.ts:4-5](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/action-async-storage-instance.ts#L4-L5), [packages/next/src/server/app-render/console-async-storage-instance.ts:4-5](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/console-async-storage-instance.ts#L4-L5), [packages/next/src/server/app-render/dynamic-access-async-storage-instance.ts:4-5](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/dynamic-access-async-storage-instance.ts#L4-L5), [packages/next/src/server/app-render/work-async-storage-instance.ts:4-5](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/work-async-storage-instance.ts#L4-L5), [packages/next/src/server/app-render/work-unit-async-storage-instance.ts:4-5](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/work-unit-async-storage-instance.ts#L4-L5)

> [!NOTE]
> Using `Symbol.for` with the Next.js version ensures that if multiple distinct versions of Next.js are evaluated within the same JavaScript realm, their async storage instances remain isolated, preventing incompatible store shape collisions.

Sources: [packages/next/src/server/app-render/async-local-storage.ts:69-72](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/async-local-storage.ts#L69-L72)

### Fallback Shims and Environment Safety

When `AsyncLocalStorage` is unavailable in the execution environment, `createAsyncLocalStorage` falls back to `FakeAsyncLocalStorage`. The fake shim implements the `AsyncLocalStorage` interface by returning `undefined` for `getStore()` and throwing an invariant error for all lifecycle operations (`disable`, `run`, `exit`, `enterWith`).

```typescript
class FakeAsyncLocalStorage<Store extends {}>
  implements AsyncLocalStorage<Store>
{
  disable(): void {
    throw sharedAsyncLocalStorageNotAvailableError
  }

  getStore(): Store | undefined {
    // This fake implementation of AsyncLocalStorage always returns `undefined`.
    return undefined
  }

  run<R>(): R {
    throw sharedAsyncLocalStorageNotAvailableError
  }

  exit<R>(): R {
    throw sharedAsyncLocalStorageNotAvailableError
  }

  enterWith(): void {
    throw sharedAsyncLocalStorageNotAvailableError
  }

  static bind<T>(fn: T): T {
    return fn
  }
}
```
Sources: [packages/next/src/server/app-render/async-local-storage.ts:7-34](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/async-local-storage.ts#L7-L34)

```typescript
export function createAsyncLocalStorage<
  Store extends {},
>(): AsyncLocalStorage<Store> {
  if (maybeGlobalAsyncLocalStorage) {
    return new maybeGlobalAsyncLocalStorage()
  }
  return new FakeAsyncLocalStorage()
}
```
Sources: [packages/next/src/server/app-render/async-local-storage.ts:39-46](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/async-local-storage.ts#L39-L46)

> [!WARNING]
> Module loader symlink resolution bugs (such as those tied to `fs.realpathSync` in `next dev` under package managers like pnpm) can cause the same file to be evaluated multiple times in a single realm, creating duplicate module instances. Storing singletons on `globalThis` via symbol keys prevents context loss across these duplicate module evaluations.

Sources: [packages/next/src/server/app-render/async-local-storage.ts:50-68](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/async-local-storage.ts#L50-L68)

For client-side compilation, `server-async-storage.ts` is aliased to `server-async-storage.browser.ts`, exporting `undefined` stubs for `actionAsyncStorage`, `workAsyncStorage`, and `workUnitAsyncStorage` to prevent server-only modules from leaking into browser bundles.

```typescript
// Browser variant of `./server-async-storage`. The server-only async-storage
// singletons don't exist in the browser, so these are `undefined`. Consumers
// guard usage behind `typeof window === 'undefined'`, so the stubs are never
// dereferenced.
export const actionAsyncStorage = undefined
export const workAsyncStorage = undefined
export const workUnitAsyncStorage = undefined
```
Sources: [packages/next/src/client/components/server-async-storage.browser.ts:1-7](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/server-async-storage.browser.ts#L1-L7), [packages/next/src/client/components/server-async-storage.ts:1-9](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/server-async-storage.ts#L1-L9)

## Work Store Lifecycle

### Store Creation and Prerender Configuration

The `WorkStore` is instantiated through factory functions that construct and initialize store instances based on rendering contexts and build options. The `createWorkStore` and `createPrerenderWorkStore` functions invoke `createWorkStoreImpl`, passing parameters that dictate fetch metrics tracking behavior.

| Factory Function | Metric Tracking Flag Condition |
| :--- | :--- |
| `createWorkStore` | `!!process.env.__NEXT_DEV_SERVER` |
| `createPrerenderWorkStore` | `!!process.env.__NEXT_DEV_SERVER \|\| !!process.env.NEXT_DEBUG_BUILD \|\| process.env.NEXT_SSG_FETCH_METRICS === '1'` |

Sources: [packages/next/src/server/async-storage/work-store.ts:91-102](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/async-storage/work-store.ts#L91-L102)

### Initialization and Context Capture

During initialization, `createWorkStoreImpl` maps properties from `WorkStoreContext` and `RenderOpts` directly onto the `WorkStore` object. It normalizes the route using `normalizeAppPath(page)`, resolves the [incremental cache](https://www.doc0.dev/docs/8f4009b0-65bd-4480-9b00-e201f0914bb3/technical/server-runtime/incremental-cache) by falling back to `(globalThis as any).__incrementalCache` when edge runtime local environments lack an explicit instance, and records the request start time using `performance.timeOrigin + performance.now()`.

```typescript
const store: WorkStore = {
  page,
  route: normalizeAppPath(page),
  incrementalCache:
    // we fallback to a global incremental cache for edge-runtime locally
    // so that it can access the fs cache without mocks
    renderOpts.incrementalCache || (globalThis as any).__incrementalCache,
  cacheLifeProfiles: renderOpts.cacheLifeProfiles,
  useCacheTimeout: renderOpts.experimental.useCacheTimeout,
  durableUseCacheEntries: renderOpts.experimental.durableUseCacheEntries,
  staticPageGenerationTimeout: renderOpts.staticPageGenerationTimeout,
  isBuildTimePrerendering: renderOpts.isBuildTimePrerendering,
  fetchCache: renderOpts.fetchCache,
  isOnDemandRevalidate: renderOpts.isOnDemandRevalidate,
  requestId: undefined,
  htmlRequestId: undefined,

  isDraftMode: renderOpts.isDraftMode,

  isPrefetchRequest,
  buildId,
  deploymentId,
  reactLoadableManifest: renderOpts?.reactLoadableManifest || {},
  assetPrefix: renderOpts?.assetPrefix || '',
  nonce,

  afterContext: createAfterContext(renderOpts),
  cacheComponentsEnabled: renderOpts.cacheComponents,
  validationLevel: renderOpts.validationLevel,
  previouslyRevalidatedTags,
  requestStartTime: performance.timeOrigin + performance.now(),
  refreshTagsByCacheKind: createRefreshTagsByCacheKind(),
  runInCleanSnapshot: createSnapshot(),
  shouldTrackFetchMetrics,
  clientComponentLoadTracker: undefined,
  reactServerErrorsByDigest: new Map(),
}
```
Sources: [packages/next/src/server/async-storage/work-store.ts:116-152](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/async-storage/work-store.ts#L116-L152)

> [!NOTE]
> `renderOpts.store` is temporarily assigned the newly created store reference to support legacy code paths accessing store values outside the active request execution context.

Sources: [packages/next/src/server/async-storage/work-store.ts:154-156](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/async-storage/work-store.ts#L154-L156)

### After-Context and Lazy Tag Refreshing

The lifecycle builder constructs an `AfterContext` instance using lifecycle options such as `waitUntil`, `onClose`, and `onTaskError`. Simultaneously, it initializes the `refreshTagsByCacheKind` map by iterating over available cache handler entries and wrapping handlers that expose a `refreshTags` method into `LazyResult` instances.

```typescript
function createAfterContext(renderOpts: RequestLifecycleOpts): AfterContext {
  const { waitUntil, onClose, onAfterTaskError } = renderOpts
  return new AfterContext({
    waitUntil,
    onClose,
    onTaskError: onAfterTaskError,
  })
}

/**
 * Creates a map with lazy results that refresh tags for the respective cache
 * kind when they're awaited for the first time.
 */
function createRefreshTagsByCacheKind(): Map<string, LazyResult<void>> {
  const refreshTagsByCacheKind = new Map<string, LazyResult<void>>()
  const cacheHandlers = getCacheHandlerEntries()

  if (cacheHandlers) {
    for (const [kind, cacheHandler] of cacheHandlers) {
      if ('refreshTags' in cacheHandler) {
        refreshTagsByCacheKind.set(
          kind,
          createLazyResult(async () => cacheHandler.refreshTags())
        )
      }
    }
  }

  return refreshTagsByCacheKind
}
```
Sources: [packages/next/src/server/async-storage/work-store.ts:160-189](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/async-storage/work-store.ts#L160-L189)

### Static Generation Snapshotting

[Static generation](https://www.doc0.dev/docs/8f4009b0-65bd-4480-9b00-e201f0914bb3/technical/build-system/static-generation) and cache entry creation require isolation from request-specific state. The `runInCleanSnapshot` property on the store is initialized via `createSnapshot()`, supplying a clean `AsyncLocalStorage` snapshot wrapper that prevents cache generation routines from reading request-bound scopes like `cookies()` inside `React.cache()`.

```typescript
refreshTagsByCacheKind: createRefreshTagsByCacheKind(),
runInCleanSnapshot: createSnapshot(),
```
Sources: [packages/next/src/server/async-storage/work-store.ts:147-148](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/async-storage/work-store.ts#L147-L148), [packages/next/src/server/app-render/work-async-storage.external.ts:197-200](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/work-async-storage.external.ts#L197-L200)

## Work Unit Store Hierarchy

### Common Work Unit Stores and Phase Management

Work unit stores represent different execution scopes in the [App Router](https://www.doc0.dev/docs/8f4009b0-65bd-4480-9b00-e201f0914bb3/technical/client-runtime/app-router), separating active requests, prerenders, and background tasks. Every work unit store extends `CommonWorkUnitStore`, which defines a mutable `phase` property and readonly `implicitTags`.

| Work Unit Phase | Description |
| :--- | :--- |
| `'action'` | Active execution of [Server Actions](https://www.doc0.dev/docs/8f4009b0-65bd-4480-9b00-e201f0914bb3/technical/app-rendering/server-actions) responding to client mutations |
| `'render'` | Server-side rendering of Server Component trees and route segments |
| `'after'` | Execution of deferred work via background tasks or `after` callbacks |

Sources: [packages/next/src/server/app-render/work-unit-async-storage.external.ts:28-34](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/work-unit-async-storage.external.ts#L28-L34)

### Request and Prerender Contexts

The `RequestStore` interface models active HTTP requests and supports mutable cookies, draft mode tracking, header access, and incremental resume data caches. It maintains asynchronous API promises and handles development-only flags like `needsRuntimeShell` and `hasIncompatibleShellContent` to distinguish static and runtime prerender behaviors.

```typescript
export interface RequestStore extends CommonWorkUnitStore {
  readonly type: 'request'

  /**
   * The URL of the request. This only specifies the pathname and the search
   * part of the URL.
   */
  readonly url: {
    /**
     * The pathname of the requested URL.
     */
    readonly pathname: string

    /**
     * The search part of the requested URL. If the request did not provide a
     * search part, this will be an empty string.
     */
    readonly search: string
  }

  readonly headers: ReadonlyHeaders
  // This is mutable because we need to reassign it when transitioning from the action phase to the render phase.
  // The cookie object itself is deliberately read only and thus can't be updated.
  cookies: ReadonlyRequestCookies
  readonly mutableCookies: ResponseCookies
  readonly userspaceMutableCookies: ResponseCookies
  readonly draftMode: DraftModeProvider
  readonly isHmrRefresh?: boolean
  readonly serverComponentsHmrCache?: ServerComponentsHmrCache
  readonly hmrRefreshHash?: string

  readonly rootParams: Params

  /**
   * The resume data cache for this request. Either a mutable
   * `PrerenderResumeDataCache` (e.g. during a dev warmup that fills caches) or
   * an immutable `RenderResumeDataCache` (e.g. when resuming from a postponed
   * state). Narrow via `resumeDataCache.mutable` to tell them apart.
   */
  resumeDataCache: ResumeDataCache | null

```
Sources: [packages/next/src/server/app-render/work-unit-async-storage.external.ts:36-76](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/work-unit-async-storage.external.ts#L36-L76)

> [!NOTE]
> `PrerenderStoreModern` covers client, server, and runtime prerendering modes along with validation stores, utilizing conditional properties to track cache population without explicitly branching RSC and SSR code paths.

Sources: [packages/next/src/server/app-render/work-unit-async-storage.external.ts:149-154](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/work-unit-async-storage.external.ts#L149-L154)

### Specialized Asynchronous Storages

Action execution, background tasks, and dynamic access tracking operate through dedicated `AsyncLocalStorage` instances. `ActionStore` tracks whether execution is part of an action or an App Route handler. `AfterTaskStore` captures the `rootTaskSpawnphase` corresponding to the phase in which the topmost `after` call was invoked.

```typescript
export interface ActionStore {
  readonly isAction?: boolean
  readonly isAppRoute?: boolean
}
```
Sources: [packages/next/src/server/app-render/action-async-storage.external.ts:5-8](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/action-async-storage.external.ts#L5-L8), [packages/next/src/server/app-render/after-task-async-storage.external.ts:7-14](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/after-task-async-storage.external.ts#L7-L14)

Dynamic access tracking relies on `DynamicAccessAsyncStore`, which holds an `AbortController` and a `reason` restricted to `'fallback-params'` or `'runtime'`. The `abortOnDynamicAccess` function updates the store reason unless it is already marked as `'runtime'` and aborts the associated controller.

```typescript
export interface DynamicAccessAsyncStore {
  readonly abortController: AbortController
  reason: DynamicAccessReason | null
}

export type DynamicAccessReason = 'fallback-params' | 'runtime'
```
Sources: [packages/next/src/server/app-render/dynamic-access-async-storage.external.ts:6-11](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/dynamic-access-async-storage.external.ts#L6-L11), [packages/next/src/server/app-render/dynamic-access-async-storage.external.ts:16-29](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/dynamic-access-async-storage.external.ts#L16-L29)

> [!WARNING]
> Cache evaluation routines reading both fallback and runtime parameters will upgrade the cancellation reason from fallback-only to runtime, preventing stale static optimizations when runtime data is touched.

Sources: [packages/next/src/server/app-render/dynamic-access-async-storage.external.ts:21-28](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/dynamic-access-async-storage.external.ts#L21-L28)

## Request Store Composition

### Request Store Builders and Inputs

The construction of a `RequestStore` instance relies on specialized creator functions that initialize phase contexts, route parameters, request headers, cookies, and cache references. `createRequestStoreForRender` initializes a store with a `'render'` phase by default, whereas `createRequestStoreForAPI` defaults to an `'action'` phase with empty root parameters (`{}`) and null resume data caches. Both helper functions delegate initialization to the core `createRequestStore` function, which accepts a `RequestStoreInputs` descriptor containing raw incoming request properties and optional HMR or preview properties.

| Creator Function | Default Phase | Root Parameters | Resume Data Cache |
| :--- | :--- | :--- | :--- |
| `createRequestStoreForRender` | `'render'` | `rootParams` (passed) | `resumeDataCache` |
| `createRequestStoreForAPI` | `'action'` | `{}` (empty) | `null` |

Sources: [packages/next/src/server/async-storage/request-store.ts:184-244](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/async-storage/request-store.ts#L184-L244)

> [!NOTE]
> Side-process consumers, such as the `'use cache'` deadlock probe worker, invoke `createRequestStore` directly with a serializable snapshot of headers and metadata when a native `req`/`res` pair is absent.

Sources: [packages/next/src/server/async-storage/request-store.ts:246-253](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/async-storage/request-store.ts#L246-L253)

### Caching and Lazy Initialization

The `RequestStore` object uses internal lazy getters backed by a private `cache` object to construct and memoize expensive adapter instances on first access. Properties including `headers`, `cookies`, `mutableCookies`, `userspaceMutableCookies`, and `draftMode` are instantiated on demand, preventing unnecessary parsing overhead for requests that do not touch them.

```typescript
const cache: {
  headers?: ReadonlyHeaders
  cookies?: ReadonlyRequestCookies
  mutableCookies?: ResponseCookies
  userspaceMutableCookies?: ResponseCookies
  draftMode?: DraftModeProvider
} = {}

return {
  type: 'request',
  phase,
  implicitTags,
  // Rather than just using the whole `url` here, we pull the parts we want
  // to ensure we don't use parts of the URL that we shouldn't. This also
  // lets us avoid requiring an empty string for `search` in the type.
  url: { pathname: url.pathname, search: url.search ?? '' },
  rootParams,
  get headers() {
    if (!cache.headers) {
      // Seal the headers object that'll freeze out any methods that could
      // mutate the underlying data.
      cache.headers = getHeaders(headers)
    }

    return cache.headers
  },
  get cookies() {
    if (!cache.cookies) {
      // if middleware is setting cookie(s), then include those in
      // the initial cached cookies so they can be read in render
      const requestCookies = new RequestCookies(HeadersAdapter.from(headers))

      mergeMiddlewareCookies(headers, requestCookies)

      // Seal the cookies object that'll freeze out any methods that could
      // mutate the underlying data.
      cache.cookies = RequestCookiesAdapter.seal(requestCookies)
    }

    return cache.cookies
  },
  set cookies(value: ReadonlyRequestCookies) {
    cache.cookies = value
  },
  get mutableCookies() {
    if (!cache.mutableCookies) {
      const mutableCookies = getMutableCookies(headers, onUpdateCookies)

      mergeMiddlewareCookies(headers, mutableCookies)

      cache.mutableCookies = mutableCookies
    }
    return cache.mutableCookies
  },
  get userspaceMutableCookies() {
    if (!cache.userspaceMutableCookies) {
      const userspaceMutableCookies =
        createCookiesWithMutableAccessCheck(this)
      cache.userspaceMutableCookies = userspaceMutableCookies
    }
    return cache.userspaceMutableCookies
  },
  get draftMode() {
    if (!cache.draftMode) {
      cache.draftMode = new DraftModeProvider(
        previewProps,
        headers,
        this.cookies,
        this.mutableCookies
      )
    }

    return cache.draftMode
  },
```
Sources: [packages/next/src/server/async-storage/request-store.ts:269-342](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/async-storage/request-store.ts#L269-L342)

Cookie initialization parses request cookies from headers and automatically merges any middleware-set cookies present in the `'x-middleware-set-cookie'` header via `mergeMiddlewareCookies`. The sealed `cookies` property returns a read-only adapter, while `mutableCookies` provides a `ResponseCookies` instance capable of tracking modifications and triggering `onUpdateCookies` callbacks.

```typescript
get cookies() {
  if (!cache.cookies) {
    // if middleware is setting cookie(s), then include those in
    // the initial cached cookies so they can be read in render
    const requestCookies = new RequestCookies(HeadersAdapter.from(headers))

    mergeMiddlewareCookies(headers, requestCookies)

    // Seal the cookies object that'll freeze out any methods that could
    // mutate the underlying data.
    cache.cookies = RequestCookiesAdapter.seal(requestCookies)
  }

  return cache.cookies
},
set cookies(value: ReadonlyRequestCookies) {
  cache.cookies = value
},
get mutableCookies() {
  if (!cache.mutableCookies) {
    const mutableCookies = getMutableCookies(headers, onUpdateCookies)

    mergeMiddlewareCookies(headers, mutableCookies)

    cache.mutableCookies = mutableCookies
  }
  return cache.mutableCookies
},
```
Sources: [packages/next/src/server/async-storage/request-store.ts:295-322](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/async-storage/request-store.ts#L295-L322)

### Draft Mode and Phase Synchronization

Draft mode evaluation is handled by the `DraftModeProvider` class, which inspects incoming headers for on-demand revalidation flags and validates the prerender bypass cookie against the configured `previewModeId`. In non-production environments, `previewModeId` accepts a `'development-id'` fallback match regardless of the exact cookie hash value.

| Method / Getter | Action Description |
| :--- | :--- |
| `isEnabled` | Evaluates whether the prerender bypass cookie matches the preview ID and on-demand revalidation is absent |
| `enable()` | Sets the prerender bypass cookie (`__prerender_bypass`) into mutable cookies with `httpOnly: true` and path `/` |
| `disable()` | Expires the prerender bypass cookie immediately by setting `expires: new Date(0)` |

Sources: [packages/next/src/server/async-storage/draft-mode-provider.ts:11-94](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/async-storage/draft-mode-provider.ts#L11-L94)

> [!CAUTION]
> Calling `enable()` when `previewModeId` is undefined throws an immediate invariant error because the bypass cookie value cannot be determined.

Sources: [packages/next/src/server/async-storage/draft-mode-provider.ts:59-65](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/async-storage/draft-mode-provider.ts#L59-L65)

When request phases transition or mutable cookies are updated, `synchronizeMutableCookies` converts updated response cookies back into sealed request cookies so subsequent reads reflect the mutations.

```typescript
export function synchronizeMutableCookies(store: RequestStore) {
  // TODO: does this need to update headers as well?
  store.cookies = RequestCookiesAdapter.seal(
    responseCookiesToRequestCookies(store.mutableCookies)
  )
}
```
Sources: [packages/next/src/server/async-storage/request-store.ts:354-359](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/async-storage/request-store.ts#L354-L359)

## Request Data Access Enforcement

### Dynamic Resolution and Bailout Guards

When application code invokes `headers()`, `cookies()`, or `draftMode()`, Next.js resolves the request data context via `workAsyncStorage` and `workUnitAsyncStorage`. If either store is missing, execution immediately invokes `throwForMissingRequestStore`. When a work store is present, calls enforce structural constraints, starting with phase validation: if a `workUnitStore` is active and `isRequestApiAllowedInCurrentPhase` evaluates to false, accessing `cookies()` or `headers()` inside an `after()` callback throws an unsupported usage error. If `workStore.forceStatic` is enabled, all dynamic enforcement logic is bypassed, returning an empty, untracked cookies or headers object. If `workStore.dynamicShouldError` is true, a `StaticGenBailoutError` is thrown, aborting static generation.

Sources: [packages/next/src/server/request/cookies.ts:36-60](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/request/cookies.ts#L36-L60), [packages/next/src/server/request/headers.ts:43-94](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/request/headers.ts#L43-L94)

> [!WARNING]
> Accessing `cookies()` or `headers()` inside a `"use cache"` block or an `unstable_cache` invocation throws specialized cache error messages (`createCookiesInUseCacheError`, `createHeadersInUseCacheError`, or their unstable counterparts) to prevent non-deterministic dynamic reads inside cached boundaries.

Sources: [packages/next/src/server/request/cookies.ts:61-70](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/request/cookies.ts#L61-L70), [packages/next/src/server/request/headers.ts:62-72](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/request/headers.ts#L62-L72)

### Work Unit Store Resolution Branches

Depending on the specific `workUnitStore.type`, request data access follows distinct execution branches that determine whether data is tracked, delayed, or rejected.

| Work Unit Store Type | `cookies()` Behavior | `headers()` Behavior |
| :--- | :--- | :--- |
| `'cache'` / `'unstable-cache'` | Throws use-cache or unstable-cache error | Throws use-cache or unstable-cache error |
| `'build-time-generator'` | Throws wrong-context build time error | Throws wrong-context build time error |
| `'prerender'` | Returns hanging session data promise | Returns hanging session data promise |
| `'prerender-client'` / `'validation-client'` | Throws `InvariantError` (Client Component usage) | Throws `InvariantError` (Client Component usage) |
| `'prerender-legacy'` | Interrupts static generation (`throwToInterruptStaticGeneration`) | Interrupts static generation (`throwToInterruptStaticGeneration`) |
| `'prerender-runtime'` | Delays via `stagedRendering` or returns untracked | Delays via `stagedRendering` or returns untracked |
| `'private-cache'` | Returns untracked `workUnitStore.cookies` | Returns untracked `workUnitStore.headers` |
| `'request'` | Tracks dynamic data and returns mutable or readonly cookies | Tracks dynamic data and returns headers |

Sources: [packages/next/src/server/request/cookies.ts:61-142](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/request/cookies.ts#L61-L142), [packages/next/src/server/request/headers.ts:62-153](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/request/headers.ts#L62-L153)

### Draft Mode Access and Mutation Tracking

The `draftMode()` function returns a promise resolving to a `DraftMode` instance. Accessing `.isEnabled` or invoking `.enable()` and `.disable()` triggers specific enforcement paths. In development environments without a prefetch request, `draftMode()` returns a proxied promise instrumented with `createDraftModeWithDevWarnings` that logs errors if properties are accessed synchronously without unwrapping the promise via `await` or `React.use()`.

```typescript
function createDraftModeWithDevWarnings(
  underlyingProvider: null | DraftModeProvider,
  route: undefined | string
): Promise<DraftMode> {
  const instance = new DraftMode(underlyingProvider)
  const promise = Promise.resolve(instance)

  const proxiedPromise = new Proxy(promise, {
    get(target, prop, receiver) {
      switch (prop) {
        case 'isEnabled':
          warnForSyncAccess(route, `\`draftMode().${prop}\``)
          break
        case 'enable':
        case 'disable': {
          warnForSyncAccess(route, `\`draftMode().${prop}()\``)
          break
        }
        default: {
          // We only warn for well-defined properties of the draftMode object.
        }
      }

      return ReflectAdapter.get(target, prop, receiver)
    },
  })

  return proxiedPromise
}
```
Sources: [packages/next/src/server/request/draft-mode.ts:118-146](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/request/draft-mode.ts#L118-L146)

When `.enable()` or `.disable()` is called, `trackDynamicDraftMode` verifies that the current work unit phase is not `'after'`, throws a `StaticGenBailoutError` if `dynamicShouldError` is enabled, and handles cache and prerender boundaries:

- `'cache'` and `'private-cache'` throw `createDraftModeMutationInUseCacheError`.
- `'unstable-cache'` throws `createDraftModeMutationInUnstableCacheError`.
- `'prerender'` and `'prerender-runtime'` trigger an abort and throw synchronous request access errors requiring `await connection()`.
- `'prerender-legacy'` sets `workUnitStore.revalidate = 0` and throws a `DynamicServerError`.

Sources: [packages/next/src/server/request/draft-mode.ts:194-271](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/request/draft-mode.ts#L194-L271)

## Context Propagation Across Tasks

### Test Modes and Request Context Propagation

Next.js propagates test parameters, proxy routing ports, and test data across asynchronous task boundaries using specialized `AsyncLocalStorage` instances. The test mode infrastructure defines `TestReqInfo` objects containing a request URL, `proxyPort` number, and `testData` string, extracted from incoming requests via `TestRequestReader` implementations.

```typescript
export interface TestReqInfo {
  url: string
  proxyPort: number
  testData: string
}
```
Sources: [packages/next/src/experimental/testmode/context.ts:3-7](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/experimental/testmode/context.ts#L3-L7)

The `withRequest` helper checks for the presence of the `next-test-proxy-port` header on incoming requests. If found, it runs the provided asynchronous or synchronous callback within the `testStorage` AsyncLocalStorage context; otherwise, it executes the callback directly.

```typescript
function extractTestInfoFromRequest<R>(
  req: R,
  reader: TestRequestReader<R>
): TestReqInfo | undefined {
  const proxyPortHeader = reader.header(req, 'next-test-proxy-port')
  if (!proxyPortHeader) {
    return undefined
  }
  const url = reader.url(req)
  const proxyPort = Number(proxyPortHeader)
  const testData = reader.header(req, 'next-test-data') || ''
  return { url, proxyPort, testData }
}

export function withRequest<R, T>(
  req: R,
  reader: TestRequestReader<R>,
  fn: () => T
): T {
  const testReqInfo = extractTestInfoFromRequest(req, reader)
  if (!testReqInfo) {
    return fn()
  }
  return testStorage.run(testReqInfo, fn)
}
```
Sources: [packages/next/src/experimental/testmode/context.ts:16-40](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/experimental/testmode/context.ts#L16-L40)

To retrieve the current test context, `getTestReqInfo` checks the active `testStorage` store first, falling back to an explicit request extraction if optional parameters are provided.

```typescript
export function getTestReqInfo<R>(
  req?: R,
  reader?: TestRequestReader<R>
): TestReqInfo | undefined {
  const testReqInfo = testStorage.getStore()
  if (testReqInfo) {
    return testReqInfo
  }
  if (req && reader) {
    return extractTestInfoFromRequest(req, reader)
  }
  return undefined
}
```
Sources: [packages/next/src/experimental/testmode/context.ts:42-54](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/experimental/testmode/context.ts#L42-L54)

### Tracing Spans and Platform Contexts

Request tracing spans and platform-provided request contexts bridge low-level server initialization and runtime execution via dedicated storage layers. [Request insights](https://www.doc0.dev/docs/8f4009b0-65bd-4480-9b00-e201f0914bb3/technical/development/request-insights) identity tracking (`RequestInsightsIdentity`) covers the portion of `BaseServer` request handling that executes before App Render initializes work storage (`workAsyncStorage`).

```typescript
export type RequestInsightsIdentity = {
  requestId: string
  kind?: RequestInsightKind
  htmlRequestId: string
  url: string | undefined
}
```
Sources: [packages/next/src/server/lib/trace/request-insights-identity.ts:5-10](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/lib/trace/request-insights-identity.ts#L5-L10)

This metadata is managed through a global AsyncLocalStorage store instance initialized via `request-insights-identity-storage`.

```typescript
// This storage covers the part of BaseServer request handling that runs before
// App Render creates workAsyncStorage. Once available, workStore remains the
// primary identity source for locally recorded spans.
function getRequestInsightsIdentityStorage(): AsyncLocalStorage<RequestInsightsIdentity> {
  return getOrCreateGlobalAsyncLocalStorage('request-insights-identity-storage')
}

export function runWithRequestInsightsIdentity<T>(
  identity: RequestInsightsIdentity,
  fn: () => T
): T {
  return getRequestInsightsIdentityStorage().run(identity, fn)
}

export function getRequestInsightsIdentity():
  | RequestInsightsIdentity
  | undefined {
  return getRequestInsightsIdentityStorage().getStore()
}
```
Sources: [packages/next/src/server/lib/trace/request-insights-identity.ts:12-30](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/lib/trace/request-insights-identity.ts#L12-L30)

Similarly, platform-provided request contexts (such as those containing `waitUntil` promises for deferred execution) are stored on `globalThis` under the symbol `@next/request-context`. `getBuiltinRequestContext` resolves this symbol from global state, while `createLocalRequestContext` wraps an `AsyncLocalStorage` instance to expose a `.get()` and `.run()` interface matching platform requirements.

```typescript
export function getBuiltinRequestContext():
  | BuiltinRequestContextValue
  | undefined {
  const _globalThis = globalThis as GlobalThisWithRequestContext
  const ctx = _globalThis[NEXT_REQUEST_CONTEXT_SYMBOL]
  return ctx?.get()
}

const NEXT_REQUEST_CONTEXT_SYMBOL = Symbol.for('@next/request-context')

type GlobalThisWithRequestContext = typeof globalThis & {
  [NEXT_REQUEST_CONTEXT_SYMBOL]?: BuiltinRequestContext
}

/** A request context provided by the platform. */
export type BuiltinRequestContext = {
  get(): BuiltinRequestContextValue | undefined
}

export type RunnableBuiltinRequestContext = BuiltinRequestContext & {
  run<T>(value: BuiltinRequestContextValue, callback: () => T): T
}

export type BuiltinRequestContextValue = {
  waitUntil?: WaitUntil
}
export type WaitUntil = (promise: Promise<any>) => void

/** "@next/request-context" has a different signature from AsyncLocalStorage,
 * matching [AsyncContext.Variable](https://github.com/tc39/proposal-async-context).
 * We don't need a full AsyncContext adapter here, just having `.get()` is enough
 */
export function createLocalRequestContext(): RunnableBuiltinRequestContext {
  const storage = createAsyncLocalStorage<BuiltinRequestContextValue>()
  return {
    get: () => storage.getStore(),
    run: (value, callback) => storage.run(value, callback),
  }
}
```
Sources: [packages/next/src/server/after/builtin-request-context.ts:3-41](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/after/builtin-request-context.ts#L3-L41)

## Related

- [Request Lifecycle](https://www.doc0.dev/docs/8f4009b0-65bd-4480-9b00-e201f0914bb3/technical/server-runtime/request-lifecycle)
- [App Rendering](https://www.doc0.dev/docs/8f4009b0-65bd-4480-9b00-e201f0914bb3/technical/app-rendering/app-rendering)


## Sitemap

See the full [sitemap](https://www.doc0.dev/docs/8f4009b0-65bd-4480-9b00-e201f0914bb3/llms.txt) for all pages in this wiki.
