---
title: "Server Actions"
description: "Server Actions enable asynchronous functions defined on the server to be securely invoked from client components and form submissions, bridging client-side interactions and server-side mutations wi..."
last_updated: "2026-09-23T10:52:03.167933+00:00"
canonical_url: "https://www.doc0.dev/docs/8f4009b0-65bd-4480-9b00-e201f0914bb3/technical/app-router-rendering/server-actions"
---

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

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

- [packages/next/src/server/app-render/action-handler.ts](https://github.com/blade47/next.js/blob/main/packages/next/src/server/app-render/action-handler.ts)
- [packages/next/src/client/components/router-reducer/reducers/server-action-reducer.ts](https://github.com/blade47/next.js/blob/main/packages/next/src/client/components/router-reducer/reducers/server-action-reducer.ts)
- [packages/next/src/server/dev/hot-reloader-turbopack.ts](https://github.com/blade47/next.js/blob/main/packages/next/src/server/dev/hot-reloader-turbopack.ts)
- [packages/next/src/server/app-render/encryption.ts](https://github.com/blade47/next.js/blob/main/packages/next/src/server/app-render/encryption.ts)
- [packages/next/src/server/base-server.ts](https://github.com/blade47/next.js/blob/main/packages/next/src/server/base-server.ts)
- [packages/next/src/client/app-call-server.ts](https://github.com/blade47/next.js/blob/main/packages/next/src/client/app-call-server.ts)
- [packages/next/src/client/dev/hot-reloader/app/hot-reloader-app.tsx](https://github.com/blade47/next.js/blob/main/packages/next/src/client/dev/hot-reloader/app/hot-reloader-app.tsx)
- [packages/next/src/client/form-shared.tsx](https://github.com/blade47/next.js/blob/main/packages/next/src/client/form-shared.tsx)
- [packages/next/src/client/app-dir/form.tsx](https://github.com/blade47/next.js/blob/main/packages/next/src/client/app-dir/form.tsx)
- [packages/next/src/server/app-render/react-server.node.ts](https://github.com/blade47/next.js/blob/main/packages/next/src/server/app-render/react-server.node.ts)
- [packages/next/src/server/lib/server-action-request-meta.ts](https://github.com/blade47/next.js/blob/main/packages/next/src/server/lib/server-action-request-meta.ts)
- [packages/next/src/server/app-render/use-flight-response.tsx](https://github.com/blade47/next.js/blob/main/packages/next/src/server/app-render/use-flight-response.tsx)
- [packages/next/src/server/request/params.ts](https://github.com/blade47/next.js/blob/main/packages/next/src/server/request/params.ts)
- [packages/next/src/client/app-index.tsx](https://github.com/blade47/next.js/blob/main/packages/next/src/client/app-index.tsx)
- [packages/next/src/server/mcp/tools/get-server-action-by-id.ts](https://github.com/blade47/next.js/blob/main/packages/next/src/server/mcp/tools/get-server-action-by-id.ts)
- [packages/next/src/client/components/app-router-instance.ts](https://github.com/blade47/next.js/blob/main/packages/next/src/client/components/app-router-instance.ts)
- [packages/next/src/client/form.tsx](https://github.com/blade47/next.js/blob/main/packages/next/src/client/form.tsx)
- [packages/next/src/server/app-render/encryption-utils.ts](https://github.com/blade47/next.js/blob/main/packages/next/src/server/app-render/encryption-utils.ts)
- [packages/next/src/next-devtools/dev-overlay.browser.tsx](https://github.com/blade47/next.js/blob/main/packages/next/src/next-devtools/dev-overlay.browser.tsx)
- [packages/next/src/server/app-render/manifests-singleton.ts](https://github.com/blade47/next.js/blob/main/packages/next/src/server/app-render/manifests-singleton.ts)
- [packages/next/src/server/after/index.ts](https://github.com/blade47/next.js/blob/main/packages/next/src/server/after/index.ts)
- [packages/next/src/shared/lib/server-reference-info.ts](https://github.com/blade47/next.js/blob/main/packages/next/src/shared/lib/server-reference-info.ts)
- [packages/next/src/client/components/segment-cache/cache.ts](https://github.com/blade47/next.js/blob/main/packages/next/src/client/components/segment-cache/cache.ts)
</details>

## Overview

Server Actions enable asynchronous functions defined on the server to be securely invoked from client components and form submissions, bridging client-side interactions and server-side mutations without requiring manual API route boilerplate. By handling execution pipelines, cryptographic bound argument verification, request routing, and router state reconciliation, Server Actions integrate seamlessly into Next.js rendering and caching systems.

Sources: [packages/next/src/server/app-render/action-handler.ts:1300-1354](https://github.com/blade47/next.js/blob/main/packages/next/src/server/app-render/action-handler.ts#L1300-L1354), [packages/next/src/server/app-render/encryption.ts:48-96](https://github.com/blade47/next.js/blob/main/packages/next/src/server/app-render/encryption.ts#L48-L96), [packages/next/src/client/components/router-reducer/reducers/server-action-reducer.ts:104-147](https://github.com/blade47/next.js/blob/main/packages/next/src/client/components/router-reducer/reducers/server-action-reducer.ts#L104-L147)

## Client Action Dispatch and Form Invocation

### Overview

Client-side server action invocation starts through the `callServer` function, which wraps action identifiers and arguments into a React transition. When invoked, `callServer` delegates execution to the app router's action queue via `dispatchAppRouterAction`.

Sources: [packages/next/src/client/app-call-server.ts:5-17](https://github.com/blade47/next.js/blob/main/packages/next/src/client/app-call-server.ts#L5-L17)

### Action Queue and Dispatch Execution

The action queue manages asynchronous transitions, action ordering, and concurrency state through `AppRouterActionQueue` and `dispatchAction`. When an action payload is dispatched, a deferred promise is created and registered with React via `startTransition`. The call-chain execution walkthrough for processing actions proceeds through the following steps: `dispatchAction()` creates a deferred promise and `ActionQueueNode`, checks if `actionQueue.pending === null`, immediately invokes `runAction()` if empty, executes the action via `actionQueue.action()`, triggers `handleResult()` upon resolution, and advances the queue via `runRemainingActions()`.

Sources: [packages/next/src/client/components/app-router-instance.ts:71-144](https://github.com/blade47/next.js/blob/main/packages/next/src/client/components/app-router-instance.ts#L71-L144), [packages/next/src/client/components/app-router-instance.ts:146-216](https://github.com/blade47/next.js/blob/main/packages/next/src/client/components/app-router-instance.ts#L146-L216)

> [!NOTE]
> Navigations (`ACTION_NAVIGATE` and `ACTION_RESTORE`) take immediate priority over pending actions. When a navigation action arrives while the queue is non-empty, the current pending action is marked as `discarded = true` so its state is never applied, and the navigation starts immediately while preserving subsequent queued nodes.
> Sources: [packages/next/src/client/components/app-router-instance.ts:191-208](https://github.com/blade47/next.js/blob/main/packages/next/src/client/components/app-router-instance.ts#L191-L208)

### Form Submissions and URL Handling

Client-side form submissions are intercepted by `<Form>` components across both the App and Pages routers. The submission handler validates action URLs, inspects submitter attributes, and extracts form data into search parameters or payloads.

Sources: [packages/next/src/client/app-dir/form.tsx:147-224](https://github.com/blade47/next.js/blob/main/packages/next/src/client/app-dir/form.tsx#L147-L224), [packages/next/src/client/form.tsx:90-169](https://github.com/blade47/next.js/blob/main/packages/next/src/client/form.tsx#L90-L169)

| Form Property / Attribute | Disallowed in `<Form>` | Purpose / Handling |
| :--- | :--- | :--- |
| `method` | Yes (`DISALLOWED_FORM_PROPS`) | Disallowed directly on `<Form>`; only `get` method is supported for navigating forms. |
| `encType` | Yes (`DISALLOWED_FORM_PROPS`) | Disallowed directly on `<Form>`; only `application/x-www-form-urlencoded` is supported. |
| `target` | Yes (`DISALLOWED_FORM_PROPS`) | Disallowed directly on `<Form>`; only `_self` target is supported. |

Sources: [packages/next/src/client/form-shared.tsx:3-3](https://github.com/blade47/next.js/blob/main/packages/next/src/client/form-shared.tsx#L3-L3), [packages/next/src/client/form-shared.tsx:128-132](https://github.com/blade47/next.js/blob/main/packages/next/src/client/form-shared.tsx#L128-L132)

> [!WARNING]
> File inputs are only supported if the `<Form>` component's `action` prop is a function (Server Action). If `action` is a string URL, file inputs cannot be encoded as search parameters and trigger a development warning, falling back to the filename string value.
> Sources: [packages/next/src/client/form-shared.tsx:83-96](https://github.com/blade47/next.js/blob/main/packages/next/src/client/form-shared.tsx#L83-L96)

## Bound Argument Cryptographic Security

### Overview

Server actions often rely on closure-captured variables, known as bound arguments, which are serialized and transmitted between the client and server. To prevent tampering and ensure confidentiality, Next.js secures these closure arguments using authenticated symmetric encryption. The encryption pipeline leverages the Web Crypto API (`crypto.subtle`) with the `AES-GCM` algorithm, initialized using either an environment variable (`NEXT_SERVER_ACTIONS_ENCRYPTION_KEY`) or a manifest-provided key.

Sources: [packages/next/src/server/app-render/encryption.ts:45-70](https://github.com/blade47/next.js/blob/main/packages/next/src/server/app-render/encryption.ts#L45-L70), [packages/next/src/server/app-render/encryption-utils.ts:37-91](https://github.com/blade47/next.js/blob/main/packages/next/src/server/app-render/encryption-utils.ts#L37-L91)

### Encryption and Integrity Verification Flow

When encoding or decoding server action bound arguments, Next.js follows a strict serialization and cryptographic pipeline. The process guarantees both confidentiality via AES-GCM and integrity by prefixing the plaintext payload with the target action ID. The call-chain execution walkthrough for encrypting bound arguments proceeds as follows: `encryptActionBoundArgs()` retrieves `workUnitAsyncStorage` and client module manifests, serializes arguments via `renderToReadableStream` and `streamToString`, invokes `encodeActionBoundArg()`, generates 16 random initialization vector bytes via `crypto.getRandomValues()`, runs `encrypt()` with `AES-GCM` using `actionId + arg` as plaintext, and encodes the IV and ciphertext into base64 via `btoa()`.

Sources: [packages/next/src/server/app-render/encryption.ts:72-96](https://github.com/blade47/next.js/blob/main/packages/next/src/server/app-render/encryption.ts#L72-L96), [packages/next/src/server/app-render/encryption.ts:108-219](https://github.com/blade47/next.js/blob/main/packages/next/src/server/app-render/encryption.ts#L108-L219), [packages/next/src/server/app-render/encryption-utils.ts:37-50](https://github.com/blade47/next.js/blob/main/packages/next/src/server/app-render/encryption-utils.ts#L37-L50)

Conversely, the decoding pipeline executes: `decodeActionBoundArg()` fetches the encryption key via `getActionEncryptionKey()`, decodes the base64 payload via `atob()`, extracts the first 16 bytes as initialization vector (`ivValue`) and remaining bytes as ciphertext (`payload`), decrypts via `decrypt()`, checks if decrypted text starts with `actionId` as a checksum invariant, and returns the sliced argument payload.

Sources: [packages/next/src/server/app-render/encryption.ts:48-70](https://github.com/blade47/next.js/blob/main/packages/next/src/server/app-render/encryption.ts#L48-L70), [packages/next/src/server/app-render/encryption-utils.ts:52-65](https://github.com/blade47/next.js/blob/main/packages/next/src/server/app-render/encryption-utils.ts#L52-L65)

> [!WARNING]
> During decryption, Next.js explicitly verifies that the decrypted plaintext starts with the expected `actionId`. If this prefix check fails, it immediately throws an `Invalid Server Action payload: failed to decrypt.` error, preventing cross-action replay attacks and payload substitution.
> Sources: [packages/next/src/server/app-render/encryption.ts:65-67](https://github.com/blade47/next.js/blob/main/packages/next/src/server/app-render/encryption.ts#L65-L67)

### Cryptographic Utility and Manifest Configuration

Encryption utilities depend on helper functions to bridge binary buffers and string representations, safely managing V8 argument limits and raw crypto keys.

Sources: [packages/next/src/server/app-render/encryption-utils.ts:6-91](https://github.com/blade47/next.js/blob/main/packages/next/src/server/app-render/encryption-utils.ts#L6-L91)

| Utility Function | Parameters | Return Type | Purpose / Description |
| :--- | :--- | :--- | :--- |
| `arrayBufferToString` | `buffer: ArrayBuffer \| Uint8Array` | `string` | Converts byte buffers to binary strings, handling V8's 65,535 argument limit via `String.fromCharCode` batching or iteration. |
| `stringToUint8Array` | `binary: string` | `Uint8Array` | Converts a binary string into a `Uint8Array` using character codes. |
| `encrypt` | `key: CryptoKey, iv: Uint8Array, data: Uint8Array` | `Promise<ArrayBuffer>` | Encrypts data using `crypto.subtle.encrypt` with the `AES-GCM` algorithm. |
| `decrypt` | `key: CryptoKey, iv: Uint8Array, data: Uint8Array` | `Promise<ArrayBuffer>` | Decrypts data using `crypto.subtle.decrypt` with the `AES-GCM` algorithm. |
| `getActionEncryptionKey` | *None* | `Promise<CryptoKey>` | Resolves the encryption key from `NEXT_SERVER_ACTIONS_ENCRYPTION_KEY` or `serverActionsManifest.encryptionKey`, importing it via `crypto.subtle.importKey`. |

Sources: [packages/next/src/server/app-render/encryption-utils.ts:6-91](https://github.com/blade47/next.js/blob/main/packages/next/src/server/app-render/encryption-utils.ts#L6-L91)

> [!NOTE]
> The encryption key loaded via `getActionEncryptionKey()` is cached in the module-scoped variable `__next_loaded_action_key` to avoid redundant cryptographic key imports across requests.
> Sources: [packages/next/src/server/app-render/encryption-utils.ts:4-4](https://github.com/blade47/next.js/blob/main/packages/next/src/server/app-render/encryption-utils.ts#L4-L4), [packages/next/src/server/app-render/encryption-utils.ts:67-70](https://github.com/blade47/next.js/blob/main/packages/next/src/server/app-render/encryption-utils.ts#L67-L70)

## Server Request Discovery and Routing

### Overview

Server request discovery and routing handles incoming HTTP requests to determine whether they qualify as Server Actions, parses identifying headers and multipart payload metadata, resolves action modules via global manifests, and routes execution to the appropriate worker runtime or runtime environment.

Sources: [packages/next/src/server/lib/server-action-request-meta.ts:6-52](https://github.com/blade47/next.js/blob/main/packages/next/src/server/lib/server-action-request-meta.ts#L6-L52), [packages/next/src/server/app-render/manifests-singleton.ts:181-224](https://github.com/blade47/next.js/blob/main/packages/next/src/server/app-render/manifests-singleton.ts#L181-L224)

### Action Request Detection and Header Parsing

Incoming requests are inspected via `getServerActionRequestMetadata()` to extract header flags and payload structures. This function analyzes headers across standard Node `IncomingMessage`, `BaseNextRequest`, and web-standard `NextRequest` interfaces, checking for the `next-action` header and specific content types.

Sources: [packages/next/src/server/lib/server-action-request-meta.ts:6-24](https://github.com/blade47/next.js/blob/main/packages/next/src/server/lib/server-action-request-meta.ts#L6-L24)

| Request Metadata Property | Condition / Check | Purpose / Description |
| :--- | :--- | :--- |
| `actionId` | `req.headers.get(ACTION_HEADER)` or `req.headers[ACTION_HEADER]` | Extracts the target server action identifier from headers. |
| `isURLEncodedAction` | `req.method === 'POST' && contentType === 'application/x-www-form-urlencoded'` | Identifies URL-encoded POST actions (which later bail out in the action handler). |
| `isMultipartAction` | `req.method === 'POST' && contentType?.startsWith('multipart/form-data')` | Identifies multipart form data submissions carrying action payloads. |
| `isFetchAction` | `actionId !== undefined && typeof actionId === 'string' && req.method === 'POST'` | Identifies fetch-based action requests carrying a valid action header. |
| `isPossibleServerAction` | `isFetchAction \|\| isURLEncodedAction \|\| isMultipartAction` | Aggregate boolean indicating whether the request should enter action routing. |

Sources: [packages/next/src/server/lib/server-action-request-meta.ts:18-51](https://github.com/blade47/next.js/blob/main/packages/next/src/server/lib/server-action-request-meta.ts#L18-L51)

> [!NOTE]
> URL-encoded actions are not fully supported by the action handler; however, they are permitted to flow through request metadata parsing to maintain consistent HTTP behavior when standard page components receive unexpected POST submissions.
> Sources: [packages/next/src/server/lib/server-action-request-meta.ts:26-28](https://github.com/blade47/next.js/blob/main/packages/next/src/server/lib/server-action-request-meta.ts#L26-L28)

### Manifests Singleton and Worker Resolution

Next.js manages action bindings, server module maps, and client reference manifests globally via a `MANIFESTS_SINGLETON` symbol attached to `globalThis`. The `createServerModuleMap()` helper constructs a proxy that queries the server actions manifest for matching worker entries depending on the runtime environment (`edge` or `node`).

Sources: [packages/next/src/server/app-render/manifests-singleton.ts:22-37](https://github.com/blade47/next.js/blob/main/packages/next/src/server/app-render/manifests-singleton.ts#L22-L37), [packages/next/src/server/app-render/manifests-singleton.ts:181-224](https://github.com/blade47/next.js/blob/main/packages/next/src/server/app-render/manifests-singleton.ts#L181-L224)

When an action request targets a specific page, `selectWorkerForForwarding()` evaluates whether a worker exists for the current page name. If no worker matches the active page context, it falls back to selecting the first available worker capable of handling the action ID.

Sources: [packages/next/src/server/app-render/manifests-singleton.ts:250-272](https://github.com/blade47/next.js/blob/main/packages/next/src/server/app-render/manifests-singleton.ts#L250-L272)

```mermaid
graph TD
    A["Incoming Request"] --> B{"getServerActionRequestMetadata"}
    B -->|isPossibleServerAction: true| C["Check Action ID Header"]
    C -->|Missing Header| D["Throw InvariantError"]
    C -->|Valid Action ID| E["Query ServerModuleMap"]
    E --> F{"Worker Exists for Page?"}
    F -->|Yes| G["Dispatch to Local Worker"]
    F -->|No| H["selectWorkerForForwarding"]
    H --> I["Forward to Alternate Worker"]
```

Sources: [packages/next/src/server/lib/server-action-request-meta.ts:6-52](https://github.com/blade47/next.js/blob/main/packages/next/src/server/lib/server-action-request-meta.ts#L6-L52), [packages/next/src/server/app-render/manifests-singleton.ts:181-224](https://github.com/blade47/next.js/blob/main/packages/next/src/server/app-render/manifests-singleton.ts#L181-L224), [packages/next/src/server/app-render/manifests-singleton.ts:250-272](https://github.com/blade47/next.js/blob/main/packages/next/src/server/app-render/manifests-singleton.ts#L250-L272)

> [!WARNING]
> If `getActionModIdOrError()` cannot locate an `actionId` in the server module map, it throws an error indicating potential deployment skew or an invalid action request from a different deployment version.
> Sources: [packages/next/src/server/app-render/action-handler.ts:1361-1377](https://github.com/blade47/next.js/blob/main/packages/next/src/server/app-render/action-handler.ts#L1361-L1377), [packages/next/src/server/app-render/action-handler.ts:1379-1383](https://github.com/blade47/next.js/blob/main/packages/next/src/server/app-render/action-handler.ts#L1379-L1383)

## Action Execution and Render Pipeline

### Overview

Once an incoming action request has been authenticated, its module ID verified, and its arguments decoded, the request enters the execution and render pipeline. This phase manages the runtime context, enforces argument limits, synchronizes cookies and revalidations across phases, and streams Flight response payloads back to the client.

Sources: [packages/next/src/server/app-render/action-handler.ts:1300-1354](https://github.com/blade47/next.js/blob/main/packages/next/src/server/app-render/action-handler.ts#L1300-L1354), [packages/next/src/server/app-render/use-flight-response.tsx:35-154](https://github.com/blade47/next.js/blob/main/packages/next/src/server/app-render/use-flight-response.tsx#L35-L154)

### Action Execution Call-Chain

The execution sequence is coordinated by `executeActionAndPrepareForRender()`, which manages the transition of request stores from the action phase to the render phase.

Sources: [packages/next/src/server/app-render/action-handler.ts:1300-1354](https://github.com/blade47/next.js/blob/main/packages/next/src/server/app-render/action-handler.ts#L1300-L1354)

```mermaid
graph TD
    A["executeActionAndPrepareForRender"] --> B["Set requestStore.phase = action"]
    B --> C{"args.length > 1000?"}
    C -->|Yes| D["Throw Error: Args List Too Long"]
    C -->|No| E["workUnitAsyncStorage.run run action.apply"]
    E --> F["Evaluate skipPageRendering condition"]
    F --> G["Finally Block: Switch phase to render"]
    G --> H["synchronizeMutableCookies"]
    H --> I["Update workStore.isDraftMode"]
    I --> J["executeRevalidates"]
```

Sources: [packages/next/src/server/app-render/action-handler.ts:1300-1354](https://github.com/blade47/next.js/blob/main/packages/next/src/server/app-render/action-handler.ts#L1300-L1354)

> [!CAUTION]
> The argument length check enforces `SERVER_ACTION_ARGS_LIMIT = 1000`. If an incoming payload supplies more than 1000 arguments, execution aborts immediately to prevent stack overflow faults during `action.apply()`.
> Sources: [packages/next/src/server/app-render/action-handler.ts:1294-1319](https://github.com/blade47/next.js/blob/main/packages/next/src/server/app-render/action-handler.ts#L1294-L1319)

### Request Context and Phase Transition

During execution, the request store phase is explicitly managed to handle cookies, draft mode toggles, and cache revalidations.

Sources: [packages/next/src/server/app-render/action-handler.ts:1312-1352](https://github.com/blade47/next.js/blob/main/packages/next/src/server/app-render/action-handler.ts#L1312-L1352)

| Phase Property / Hook | Target Store / Function | Purpose and Behavior |
| :--- | :--- | :--- |
| `requestStore.phase` | `'action'` transitioning to `'render'` | Switches the execution context mode when shifting from userspace action execution to subsequent page rendering. |
| Cookie Synchronization | `synchronizeMutableCookies(requestStore)` | Updates immutable cookies in the render phase to reflect mutations performed via `cookies()` during the action phase. |
| Draft Mode State | `workStore.isDraftMode` | Reflects toggles to draft mode performed in `requestStore.draftMode.isEnabled` for subsequent rendering. |
| Tag/Path Revalidation | `executeRevalidates(workStore)` | Ensures all pending data revalidations called by `revalidateTag` or `revalidatePath` take effect before rendering. |

Sources: [packages/next/src/server/app-render/action-handler.ts:1312-1352](https://github.com/blade47/next.js/blob/main/packages/next/src/server/app-render/action-handler.ts#L1312-L1352)

### Flight Stream Processing and Inline Ingestion

The pipeline streams Flight responses via `getFlightStream()`, which resolves client module mappings and runtime-specific stream adapters (Node streams or web `ReadableStream` instances).

Sources: [packages/next/src/server/app-render/use-flight-response.tsx:35-154](https://github.com/blade47/next.js/blob/main/packages/next/src/server/app-render/use-flight-response.tsx#L35-L154)

```typescript
export function getFlightStream<T>(
  flightStream: Readable | BinaryStreamOf<T>,
  debugStream: Readable | ReadableStream<Uint8Array> | undefined,
  debugEndTime: number | undefined,
  nonce: string | undefined
): Promise<T>
```

Sources: [packages/next/src/server/app-render/use-flight-response.tsx:35-40](https://github.com/blade47/next.js/blob/main/packages/next/src/server/app-render/use-flight-response.tsx#L35-L40)

To inject hydration data outside standard React rendering, `createInlinedDataReadableStream()` wraps the Flight stream and formats chunks into inline script instructions using specialized bootstrap payloads.

Sources: [packages/next/src/server/app-render/use-flight-response.tsx:165-220](https://github.com/blade47/next.js/blob/main/packages/next/src/server/app-render/use-flight-response.tsx#L165-L220)

| Payload Type Constant | Value | Role in Stream Ingestion |
| :--- | :--- | :--- |
| `INLINE_FLIGHT_PAYLOAD_BOOTSTRAP` | `0` | Initializes the `self.__next_f` chunk array instruction queue. |
| `INLINE_FLIGHT_PAYLOAD_DATA` | `1` | Enqueues standard string-encoded Flight data chunks. |
| `INLINE_FLIGHT_PAYLOAD_FORM_STATE` | `2` | Serializes form state states alongside initial boot instructions. |
| `INLINE_FLIGHT_PAYLOAD_BINARY` | `3` | Encodes arbitrary binary chunk buffers in base64 format for safe script tag embedding. |

Sources: [packages/next/src/server/app-render/use-flight-response.tsx:14-18](https://github.com/blade47/next.js/blob/main/packages/next/src/server/app-render/use-flight-response.tsx#L14-L18), [packages/next/src/server/app-render/use-flight-response.tsx:227-266](https://github.com/blade47/next.js/blob/main/packages/next/src/server/app-render/use-flight-response.tsx#L227-L266)

> [!NOTE]
> If a chunk cannot be decoded as a valid UTF-8 string due to embedded binary payloads, `createInlinedDataReadableStream()` falls back to serializing the buffer as base64 via `Buffer.from()` or `btoa()` inside an `INLINE_FLIGHT_PAYLOAD_BINARY` instruction.
> Sources: [packages/next/src/server/app-render/use-flight-response.tsx:191-206](https://github.com/blade47/next.js/blob/main/packages/next/src/server/app-render/use-flight-response.tsx#L191-L206), [packages/next/src/server/app-render/use-flight-response.tsx:256-266](https://github.com/blade47/next.js/blob/main/packages/next/src/server/app-render/use-flight-response.tsx#L256-L266)

## Client State Invalidation and Reconciliation

### Overview

When a server action completes and returns its response payload, the client-side router reducer handles cache invalidation and state tree reconciliation. The reducer inspects the revalidation status returned by the server and purges stale caches to maintain data consistency.

Sources: [packages/next/src/client/components/router-reducer/reducers/server-action-reducer.ts:311-352](https://github.com/blade47/next.js/blob/main/packages/next/src/client/components/router-reducer/reducers/server-action-reducer.ts#L311-L352)

### Call-Chain Execution Walkthrough

The invalidation flow triggered by a server action response proceeds through a precise sequence of function calls to notify registered tasks and listeners:

1. `serverActionReducer` — Receives the action response state and checks if `revalidationKind !== ActionDidNotRevalidate`.
2. `invalidateEntirePrefetchCache` — Increments both route and segment cache version counters (`currentRouteCacheVersion++`, `currentSegmentCacheVersion++`) and hands off to visible link pinging and listener notification.
3. `pingInvalidationListeners` — Checks whether `invalidationListeners` is non-null, iterates over registered prefetch tasks, and evaluates `isPrefetchTaskDirty()`.
4. `notifyInvalidationListener` — Extracts the `onInvalidate` callback from the task, clears it to prevent duplicate execution, and safely invokes the user-space function inside a `try/catch` block.

Sources: [packages/next/src/client/components/router-reducer/reducers/server-action-reducer.ts:311-352](https://github.com/blade47/next.js/blob/main/packages/next/src/client/components/router-reducer/reducers/server-action-reducer.ts#L311-L352), [packages/next/src/client/components/segment-cache/cache.ts:344-353](https://github.com/blade47/next.js/blob/main/packages/next/src/client/components/segment-cache/cache.ts#L344-L353), [packages/next/src/client/components/segment-cache/cache.ts:404-441](https://github.com/blade47/next.js/blob/main/packages/next/src/client/components/segment-cache/cache.ts#L404-L441)

```mermaid
sequenceDiagram
    participant SAR as serverActionReducer
    participant IPC as invalidateEntirePrefetchCache
    participant PIL as pingInvalidationListeners
    participant NIL as notifyInvalidationListener

    SAR->>IPC: invalidateEntirePrefetchCache(nextUrl, tree)
    IPC->>PIL: pingInvalidationListeners(nextUrl, tree)
    PIL->>NIL: notifyInvalidationListener(task)
```

Sources: [packages/next/src/client/components/router-reducer/reducers/server-action-reducer.ts:311-352](https://github.com/blade47/next.js/blob/main/packages/next/src/client/components/router-reducer/reducers/server-action-reducer.ts#L311-L352), [packages/next/src/client/components/segment-cache/cache.ts:344-353](https://github.com/blade47/next.js/blob/main/packages/next/src/client/components/segment-cache/cache.ts#L344-L353), [packages/next/src/client/components/segment-cache/cache.ts:404-441](https://github.com/blade47/next.js/blob/main/packages/next/src/client/components/segment-cache/cache.ts#L404-L441)

### Revalidation Constants and Cache Invalidation Options

The router distinguishes between different forms of revalidation to optimize whether route structures, dynamic data, or static segments are cleared from memory.

Sources: [packages/next/src/client/components/router-reducer/reducers/server-action-reducer.ts:64-68](https://github.com/blade47/next.js/blob/main/packages/next/src/client/components/router-reducer/reducers/server-action-reducer.ts#L64-L68)

| Revalidation Constant | Value / Type | Meaning and Behavior |
| :--- | :--- | :--- |
| `ActionDidNotRevalidate` | `0` | Indicates the server action triggered no data mutations or revalidations. |
| `ActionDidRevalidateDynamicOnly` | `1` | Indicates revalidation was restricted to dynamic data sources. |
| `ActionDidRevalidateStaticAndDynamic` | `2` | Indicates both static and dynamic cache entries must be invalidated. |

Sources: [packages/next/src/client/components/router-reducer/reducers/server-action-reducer.ts:64-68](https://github.com/blade47/next.js/blob/main/packages/next/src/client/components/router-reducer/reducers/server-action-reducer.ts#L64-L68)

### Reconciliation Architecture and Trade-Offs

| Design Choice | Benefit | Cost |
| :--- | :--- | :--- |
| Lazy cache eviction via version increments (`currentRouteCacheVersion++`) | Avoids expensive synchronous garbage collection sweeps across all active entries upon revalidation. | Stale entries remain in memory until actively read and evicted. |
| Single global set for `invalidationListeners` | Low memory overhead and simple registration model when no granular path-based tags exist. | Scans all registered tasks on invalidation rather than filtering by affected segments. |
| Clearing `onInvalidate` callbacks immediately upon invocation | Guarantees user-space listeners execute at most once per invalidation event. | Requires tasks to re-register listeners if subsequent invalidations need tracking. |

Sources: [packages/next/src/client/components/segment-cache/cache.ts:316-353](https://github.com/blade47/next.js/blob/main/packages/next/src/client/components/segment-cache/cache.ts#L316-L353), [packages/next/src/client/components/segment-cache/cache.ts:404-440](https://github.com/blade47/next.js/blob/main/packages/next/src/client/components/segment-cache/cache.ts#L404-L440)

> [!WARNING]
> Cache invalidation does not eagerly evict items from memory. Instead, version counters (`currentRouteCacheVersion` and `currentSegmentCacheVersion`) are incremented, causing entries to be treated as stale and lazily evicted only when next read.
> Sources: [packages/next/src/client/components/segment-cache/cache.ts:321-326](https://github.com/blade47/next.js/blob/main/packages/next/src/client/components/segment-cache/cache.ts#L321-L326)

## Development Tooling and MCP Diagnostics

### Overview

The Next.js development server integrates specialized tooling for action compilation diagnostics, error overlay propagation, hot reloader management, and Model Context Protocol (MCP) inspection. Development tooling bridges server-side compilation issues with client-side runtime feedback through dedicated hmr channels and dispatcher actions.

Sources: [packages/next/src/server/dev/hot-reloader-turbopack.ts:1577-1622](https://github.com/blade47/next.js/blob/main/packages/next/src/server/dev/hot-reloader-turbopack.ts#L1577-L1622), [packages/next/src/client/dev/hot-reloader/app/hot-reloader-app.tsx:223-272](https://github.com/blade47/next.js/blob/main/packages/next/src/client/dev/hot-reloader/app/hot-reloader-app.tsx#L223-L272)

### Dev Overlay and Error Propagation

When compilation or runtime errors occur during server action evaluation or page rendering, the development overlay queues and dispatches actions across the browser boundary using `createQueuable` wrappers. The error dispatcher standardizes state transitions such as build errors, unhandled rejections, and overlay toggles before rendering within a Shadow DOM container.

Sources: [packages/next/src/next-devtools/dev-overlay.browser.tsx:130-240](https://github.com/blade47/next.js/blob/main/packages/next/src/next-devtools/dev-overlay.browser.tsx#L130-L240), [packages/next/src/next-devtools/dev-overlay.browser.tsx:253-331](https://github.com/blade47/next.js/blob/main/packages/next/src/next-devtools/dev-overlay.browser.tsx#L253-L331)

> [!NOTE]
> Events dispatched before React mounts the dispatcher are buffered in a queue and replayed via `replayQueuedEvents` once `maybeDispatch` becomes active in `useInsertionEffect`.
> Sources: [packages/next/src/next-devtools/dev-overlay.browser.tsx:128-142](https://github.com/blade47/next.js/blob/main/packages/next/src/next-devtools/dev-overlay.browser.tsx#L128-L142), [packages/next/src/next-devtools/dev-overlay.browser.tsx:293-307](https://github.com/blade47/next.js/blob/main/packages/next/src/next-devtools/dev-overlay.browser.tsx#L293-L307)

### MCP Server Action Inspection Tools

The MCP diagnostics server exposes tools such as `get_server_action_by_id` to inspect compiled server references directly from the build output directory. The tool queries `server-reference-manifest.json` to resolve execution metadata for node and edge runtime environments.

Sources: [packages/next/src/server/mcp/tools/get-server-action-by-id.ts:22-156](https://github.com/blade47/next.js/blob/main/packages/next/src/server/mcp/tools/get-server-action-by-id.ts#L22-L156)

| Field Name | Type | Description |
| :--- | :--- | :--- |
| `actionId` | `string` | Unique identifier corresponding to the server reference key in the manifest. |
| `runtime` | `string` | Execution environment target, resolved as either `'node'` or `'edge'`. |
| `filename` | `string` | Absolute or relative source file path containing the action definition. |
| `functionName` | `string` | Exported JavaScript function name, or `'inline server action'` if prefixed with `$$RSC_SERVER_ACTION_`. |

Sources: [packages/next/src/server/mcp/tools/get-server-action-by-id.ts:7-130](https://github.com/blade47/next.js/blob/main/packages/next/src/server/mcp/tools/get-server-action-by-id.ts#L7-L130)

## Related

- [App Server Rendering](https://www.doc0.dev/docs/8f4009b0-65bd-4480-9b00-e201f0914bb3/technical/app-router-rendering/app-server-rendering)
- [Router State Reducer](https://www.doc0.dev/docs/8f4009b0-65bd-4480-9b00-e201f0914bb3/technical/client-routing/router-state-reducer)


## Sitemap

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