---
title: "Server Testing Utilities"
description: "Server Testing Utilities provide experimental testing APIs and primitives designed to evaluate and verify Next.js server behavior—such as custom configuration routes and middleware matching rules—d..."
last_updated: "2026-09-23T10:52:03.16467+00:00"
canonical_url: "https://www.doc0.dev/docs/8f4009b0-65bd-4480-9b00-e201f0914bb3/technical/testing-infrastructure/server-testing-utilities"
---

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

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

- [packages/next/src/experimental/testmode/fetch.ts](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testmode/fetch.ts)
- [packages/next/src/experimental/testmode/server-edge.ts](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testmode/server-edge.ts)
- [packages/next/src/server/next-server.ts](https://github.com/blade47/next.js/blob/main/packages/next/src/server/next-server.ts)
- [packages/next/src/experimental/testmode/server.ts](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testmode/server.ts)
- [packages/next/src/server/web/adapter.ts](https://github.com/blade47/next.js/blob/main/packages/next/src/server/web/adapter.ts)
- [packages/next/src/experimental/testing/server/utils.ts](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testing/server/utils.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/experimental/testmode/proxy/server.ts](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testmode/proxy/server.ts)
- [packages/next/src/server/dev/next-dev-server.ts](https://github.com/blade47/next.js/blob/main/packages/next/src/server/dev/next-dev-server.ts)
- [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/experimental/testing/server.js](https://github.com/blade47/next.js/blob/main/packages/next/experimental/testing/server.js)
- [packages/next/src/experimental/testing/server/index.ts](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testing/server/index.ts)
- [packages/next/src/experimental/testmode/proxy/fetch-api.ts](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testmode/proxy/fetch-api.ts)
- [packages/next/src/experimental/testmode/httpget.ts](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testmode/httpget.ts)
- [packages/next/experimental/testing/server.d.ts](https://github.com/blade47/next.js/blob/main/packages/next/experimental/testing/server.d.ts)
- [packages/next/src/experimental/testmode/proxy/index.ts](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testmode/proxy/index.ts)
- [packages/next/src/server/lib/mock-request.ts](https://github.com/blade47/next.js/blob/main/packages/next/src/server/lib/mock-request.ts)
- [packages/next/src/server/app-render/instant-validation/instant-samples.ts](https://github.com/blade47/next.js/blob/main/packages/next/src/server/app-render/instant-validation/instant-samples.ts)
- [packages/next/src/experimental/testmode/context.ts](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testmode/context.ts)
- [packages/next/src/server/lib/router-server.ts](https://github.com/blade47/next.js/blob/main/packages/next/src/server/lib/router-server.ts)
- [packages/next/src/experimental/testmode/proxy/types.ts](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testmode/proxy/types.ts)
- [packages/next/src/next-devtools/server/middleware-response.ts](https://github.com/blade47/next.js/blob/main/packages/next/src/next-devtools/server/middleware-response.ts)
- [packages/next/src/server/web/sandbox/sandbox.ts](https://github.com/blade47/next.js/blob/main/packages/next/src/server/web/sandbox/sandbox.ts)
- [packages/next/experimental/testmode/proxy.js](https://github.com/blade47/next.js/blob/main/packages/next/experimental/testmode/proxy.js)
- [turbopack/packages/devlow-bench/src/interfaces/snowflake-test.ts](https://github.com/blade47/next.js/blob/main/turbopack/packages/devlow-bench/src/interfaces/snowflake-test.ts)
- [packages/next/src/client/components/segment-cache/navigation-testing-lock.ts](https://github.com/blade47/next.js/blob/main/packages/next/src/client/components/segment-cache/navigation-testing-lock.ts)
- [packages/next/src/experimental/testing/server/config-testing-utils.ts](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testing/server/config-testing-utils.ts)
- [packages/next/src/server/web/spec-extension/fetch-event.ts](https://github.com/blade47/next.js/blob/main/packages/next/src/server/web/spec-extension/fetch-event.ts)
- [packages/next/src/server/web/internal-edge-wait-until.ts](https://github.com/blade47/next.js/blob/main/packages/next/src/server/web/internal-edge-wait-until.ts)
- [packages/next/src/experimental/testing/server/middleware-testing-utils.ts](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testing/server/middleware-testing-utils.ts)
</details>

## Overview

Server Testing Utilities provide experimental testing APIs and primitives designed to evaluate and verify Next.js server behavior—such as custom configuration routes and middleware matching rules—directly in unit and integration test suites without requiring a live server instance. Sources: [packages/next/src/experimental/testing/server/config-testing-utils.ts:78-90](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testing/server/config-testing-utils.ts#L78-L90), [packages/next/src/experimental/testing/server/middleware-testing-utils.ts:19-31](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testing/server/middleware-testing-utils.ts#L19-L31)

By combining in-memory streaming request-response primitives, asynchronous request context propagation across Node.js and Edge runtimes, and local proxy daemons for testmode fetch interception, these utilities enable robust end-to-end test harnesses and deterministic assertions over routing, headers, and request lifecycles. Sources: [packages/next/src/experimental/testmode/fetch.ts:127-142](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testmode/fetch.ts#L127-L142), [packages/next/src/experimental/testmode/server.ts:36-47](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testmode/server.ts#L36-L47), [packages/next/src/experimental/testmode/proxy/server.ts:18-81](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testmode/proxy/server.ts#L18-L81), [packages/next/src/server/lib/mock-request.ts:25-138](https://github.com/blade47/next.js/blob/main/packages/next/src/server/lib/mock-request.ts#L25-L138), [packages/next/src/experimental/testmode/context.ts:14-40](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testmode/context.ts#L14-L40)

## Public Server Testing API Surface

The testing package exposes its public surface through explicit export declarations from entry points at `next/experimental/testing/server` and CommonJS mappings at `next/experimental/testing/server.js`. These entry points re-export configuration testing helpers, middleware matching utilities, and request construction functions designed to facilitate server behavior assertions. Sources: [packages/next/experimental/testing/server.js:1-2](https://github.com/blade47/next.js/blob/main/packages/next/experimental/testing/server.js#L1-L2), [packages/next/src/experimental/testing/server/index.ts:1-4](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testing/server/index.ts#L1-L4)

The module exports several core helper functions and types across its underlying utility files. The `constructRequest` function initializes an in-memory `BaseNextRequest` object wrapping `NodeNextRequest` and `MockedRequest` instances based on a provided URL, HTTP headers, and cookie dictionary. Response evaluation helpers include `getRedirectUrl` for extracting the `location` header, `getRewrittenUrl` for reading the `x-middleware-rewrite` header, and `isRewrite` for checking rewrite status. Sources: [packages/next/src/experimental/testing/server/utils.ts:8-56](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testing/server/utils.ts#L8-L56)

| Function / Export | Source File | Purpose |
| :--- | :--- | :--- |
| `constructRequest` | `src/experimental/testing/server/utils.ts` | Constructs a `BaseNextRequest` instance with optional headers and cookies. Sources: [packages/next/src/experimental/testing/server/utils.ts:8-32](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testing/server/utils.ts#L8-L32) |
| `getRedirectUrl` | `src/experimental/testing/server/utils.ts` | Extracts the redirect destination URL from response headers. Sources: [packages/next/src/experimental/testing/server/utils.ts:38-40](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testing/server/utils.ts#L38-L40) |
| `isRewrite` | `src/experimental/testing/server/utils.ts` | Returns a boolean indicating if the response represents a rewrite. Sources: [packages/next/src/experimental/testing/server/utils.ts:46-48](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testing/server/utils.ts#L46-L48) |
| `getRewrittenUrl` | `src/experimental/testing/server/utils.ts` | Retrieves the rewritten URL from the `x-middleware-rewrite` header. Sources: [packages/next/src/experimental/testing/server/utils.ts:54-56](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testing/server/utils.ts#L54-L56) |
| `unstable_getResponseFromNextConfig` | `src/experimental/testing/server/config-testing-utils.ts` | Evaluates custom `headers`, `redirects`, and `rewrites` from a `next.config.js` configuration. Sources: [packages/next/src/experimental/testing/server/config-testing-utils.ts:57-90](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testing/server/config-testing-utils.ts#L57-L90) |
| `unstable_doesMiddlewareMatch` | `src/experimental/testing/server/middleware-testing-utils.ts` | Verifies whether a middleware configuration matcher evaluates to true for a given request. Sources: [packages/next/src/experimental/testing/server/middleware-testing-utils.ts:13-40](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testing/server/middleware-testing-utils.ts#L13-L40) |

Sources: [packages/next/experimental/testing/server.js:1-2](https://github.com/blade47/next.js/blob/main/packages/next/experimental/testing/server.js#L1-L2), [packages/next/src/experimental/testing/server/index.ts:1-4](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testing/server/index.ts#L1-L4), [packages/next/src/experimental/testing/server/utils.ts:8-56](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testing/server/utils.ts#L8-L56)

## Next Config Route Evaluation Testing

### Overview

Next.js provides testing utilities for evaluating custom `headers`, `redirects`, and `rewrites` directly from a Next.js configuration object without needing to boot up a live server or listen on a network socket. The central entry point for this capability is `unstable_getResponseFromNextConfig`, which loads custom routes, matches incoming request parameters against path regular expressions and conditional constraints, and produces an authoritative `NextResponse`. Sources: [packages/next/src/experimental/testing/server/config-testing-utils.ts:57-90](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testing/server/config-testing-utils.ts#L57-L90)

### Call-Chain Execution Walkthrough

When evaluating a request against a configuration via `unstable_getResponseFromNextConfig`, execution follows a strict sequence through configuration normalization, route compilation, and rule matching:

`unstable_getResponseFromNextConfig()` → `parse()` / `constructRequest()` → `normalizeConfig()` → `loadCustomRoutes()` → `buildCustomRoute()` → `matchRoute()` → `matchHas()` → `matchRouteAndGetDestination()` → `prepareDestination()` → `NextResponse.redirect()` or `NextResponse.rewrite()`

1. **Request Parsing & Construction**: Incoming configuration parameters and target URL strings are parsed using `parse(url, true)` and wrapped into an in-memory `BaseNextRequest` via `constructRequest`. Sources: [packages/next/src/experimental/testing/server/config-testing-utils.ts:91-92](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testing/server/config-testing-utils.ts#L91-L92)
2. **Config Normalization & Route Loading**: `normalizeConfig` processes the `nextConfig` input under `PHASE_PRODUCTION_BUILD`, after which `loadCustomRoutes` extracts the raw route definitions. Sources: [packages/next/src/experimental/testing/server/config-testing-utils.ts:93-97](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testing/server/config-testing-utils.ts#L93-L97)
3. **Route Building**: Raw header, redirect, and rewrite rules are mapped into compiled testable routes using `buildCustomRoute`. Redirect routes receive exclusion filters for `/_next/`. Sources: [packages/next/src/experimental/testing/server/config-testing-utils.ts:99-110](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testing/server/config-testing-utils.ts#L99-L110)
4. **Header Evaluation**: Header rules are evaluated first. If `matchRoute` succeeds, all associated header key-value pairs are accumulated into `respHeaders`. Sources: [packages/next/src/experimental/testing/server/config-testing-utils.ts:112-119](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testing/server/config-testing-utils.ts#L112-L119)
5. **Redirect and Rewrite Evaluation**: The engine iterates over compiled `redirectRoutes` and then `rewriteRoutes`. `matchRouteAndGetDestination` calls `matchRoute` and prepares the final destination URL via `prepareDestination`. If matched, a corresponding `NextResponse.redirect` or `NextResponse.rewrite` with accumulated headers is returned immediately. If no rules match, a default `200` response is returned. Sources: [packages/next/src/experimental/testing/server/config-testing-utils.ts:120-166](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testing/server/config-testing-utils.ts#L120-L166)

> [!NOTE]
> `matchRoute` validates both the compiled regular expression (`route.regex`) and the path-to-regexp parser (`matcharams>(route.source)`). If the regex matches but parameter extraction fails unexpectedly, an explicit error is thrown. Sources: [packages/next/src/experimental/testing/server/config-testing-utils.ts:29-54](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testing/server/config-testing-utils.ts#L29-L54)

### Configuration Testing Functions and Helpers

| Function / Helper | Parameters | Return Type | Description |
| :--- | :--- | :--- | :--- |
| `unstable_getResponseFromNextConfig` | `url`, `nextConfig`, `headers`, `cookies` | `Promise<NextResponse>` | Evaluates headers, redirects, and rewrites against a config object without a server. Sources: [packages/next/src/experimental/testing/server/config-testing-utils.ts:78-90](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testing/server/config-testing-utils.ts#L78-L90) |
| `matchRoute` | `route`, `request`, `parsedUrl` | `Params \| undefined` | Matches a route against request pathname, regex, and conditional `has`/`missing` filters. Sources: [packages/next/src/experimental/testing/server/config-testing-utils.ts:29-54](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testing/server/config-testing-utils.ts#L29-L54) |
| `constructRequest` | `url`, `headers`, `cookies` | `BaseNextRequest` | Initializes an in-memory mock request wrapper for route and header evaluation. Sources: [packages/next/src/experimental/testing/server/utils.ts:8-32](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testing/server/utils.ts#L8-L32) |
| `getRedirectUrl` | `response` | `string \| null` | Extracts the `location` header value from a redirect response. Sources: [packages/next/src/experimental/testing/server/utils.ts:38-40](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testing/server/utils.ts#L38-L40) |
| `isRewrite` | `response` | `boolean` | Checks whether the response contains an `x-middleware-rewrite` header. Sources: [packages/next/src/experimental/testing/server/utils.ts:46-48](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testing/server/utils.ts#L46-L48) |
| `getRewrittenUrl` | `response` | `string \| null` | Reads the target URL from the `x-middleware-rewrite` header. Sources: [packages/next/src/experimental/testing/server/utils.ts:54-56](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testing/server/utils.ts#L54-L56) |

Sources: [packages/next/src/experimental/testing/server/config-testing-utils.ts:29-90](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testing/server/config-testing-utils.ts#L29-L90), [packages/next/src/experimental/testing/server/utils.ts:8-56](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testing/server/utils.ts#L8-L56)

### Route Evaluation Design Choices

| Design Choice | Benefit | Cost |
| :--- | :--- | :--- |
| In-memory mock request wrapping via `constructRequest` | Eliminates HTTP overhead and network port bindings during test execution. Sources: [packages/next/src/experimental/testing/server/utils.ts:8-32](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testing/server/utils.ts#L8-L32) | Cannot exercise actual TCP-level socket behaviors or low-level transport errors. Sources: [packages/next/src/experimental/testing/server/config-testing-utils.ts:57-90](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testing/server/config-testing-utils.ts#L57-L90) |
| Config normalization under `PHASE_PRODUCTION_BUILD` | Reuses production build route compilation logic identically inside tests. Sources: [packages/next/src/experimental/testing/server/config-testing-utils.ts:93-96](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testing/server/config-testing-utils.ts#L93-L96) | Tied to production build assumptions and may not reflect runtime-only server hooks. Sources: [packages/next/src/experimental/testing/server/config-testing-utils.ts:93-96](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testing/server/config-testing-utils.ts#L93-L96) |
| Sequential fallback evaluation across headers, redirects, and rewrites | Predictable execution order mirroring Next.js routing specifications. Sources: [packages/next/src/experimental/testing/server/config-testing-utils.ts:112-164](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testing/server/config-testing-utils.ts#L112-L164) | Linear scan over route arrays can be less performant for very large custom route tables. Sources: [packages/next/src/experimental/testing/server/config-testing-utils.ts:112-164](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testing/server/config-testing-utils.ts#L112-L164) |

Sources: [packages/next/src/experimental/testing/server/utils.ts:8-32](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testing/server/utils.ts#L8-L32), [packages/next/src/experimental/testing/server/config-testing-utils.ts:57-166](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testing/server/config-testing-utils.ts#L57-L166)

### Full Worked Example

```typescript
import { unstable_getResponseFromNextConfig } from '../../../src/experimental/testing/server/config-testing-utils'
import { getRedirectUrl, isRewrite, getRewrittenUrl } from '../../../src/experimental/testing/server/utils'

async function runTest() {
  // Evaluate a custom redirect rule defined directly in config
  const redirectResponse = await unstable_getResponseFromNextConfig({
    url: 'https://nextjs.org/old-blog/hello-world',
    nextConfig: {
      async redirects() {
        return [
          {
            source: '/old-blog/:slug',
            destination: '/blog/:slug',
            permanent: false,
          },
        ]
      },
    },
  })

  console.log('Status:', redirectResponse.status) // 307 or 308 depending on permanent flag
  console.log('Redirect URL:', getRedirectUrl(redirectResponse)) // https://nextjs.org/blog/hello-world

  // Evaluate custom headers and rewrites
  const rewriteResponse = await unstable_getResponseFromNextConfig({
    url: 'https://nextjs.org/profile',
    headers: { 'x-custom-header': 'test-value' },
    cookies: { session: 'xyz' },
    nextConfig: {
      async headers() {
        return [
          {
            source: '/profile',
            headers: [{ key: 'x-tested', value: 'true' }],
          },
        ]
      },
      async rewrites() {
        return {
          beforeFiles: [],
          afterFiles: [
            {
              source: '/profile',
              destination: '/user-profile',
            },
          ],
          fallback: [],
        }
      },
    },
  })

  console.log('Is Rewrite:', isRewrite(rewriteResponse)) // true
  console.log('Rewritten URL:', getRewrittenUrl(rewriteResponse)) // https://nextjs.org/user-profile
  console.log('Header x-tested:', rewriteResponse.headers.get('x-tested')) // true
}

runTest()
```

Sources: [packages/next/src/experimental/testing/server/config-testing-utils.ts:57-166](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testing/server/config-testing-utils.ts#L57-L166), [packages/next/src/experimental/testing/server/utils.ts:8-56](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testing/server/utils.ts#L8-L56)

## Middleware Execution and Matcher Testing

### Overview

The `unstable_doesMiddlewareMatch` utility evaluates whether a specific middleware configuration's matcher rules match a given URL, set of headers, and cookies. This allows unit tests to assert that middleware executes precisely when intended without booting a server runtime.

Sources: [packages/next/src/experimental/testing/server/middleware-testing-utils.ts:13-18](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testing/server/middleware-testing-utils.ts#L13-L18)

### Middleware Matching Call Chain

Evaluating a matcher rule involves constructing a mock request object, parsing URL search parameters, compiling matchers, and executing the compiled route matching function:

1. `unstable_doesMiddlewareMatch()` receives the `config`, `url`, `headers`, `cookies`, and optional `nextConfig`. Sources: [packages/next/src/experimental/testing/server/middleware-testing-utils.ts:19-31](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testing/server/middleware-testing-utils.ts#L19-L31)
2. It checks if `config.matcher` is defined; if absent, it returns `true` immediately. Sources: [packages/next/src/experimental/testing/server/middleware-testing-utils.ts:32-34](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testing/server/middleware-testing-utils.ts#L32-L34)
3. `getMiddlewareMatchers()` processes the configuration matcher input alongside `nextConfig`. Sources: [packages/next/src/experimental/testing/server/middleware-testing-utils.ts:35](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testing/server/middleware-testing-utils.ts#L35)
4. `getMiddlewareRouteMatcher()` compiles the generated matchers into an executable routing function (`routeMatchFn`). Sources: [packages/next/src/experimental/testing/server/middleware-testing-utils.ts:36](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testing/server/middleware-testing-utils.ts#L36)
5. `parseUrl(url)` extracts the `pathname` and `searchParams`. Sources: [packages/next/src/experimental/testing/server/middleware-testing-utils.ts:37](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testing/server/middleware-testing-utils.ts#L37)
6. `constructRequest()` builds a `BaseNextRequest` wrapping a `NodeNextRequest` and `MockedRequest` containing the supplied URL, populated headers, and serialized cookies. Sources: [packages/next/src/experimental/testing/server/middleware-testing-utils.ts:38](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testing/server/middleware-testing-utils.ts#L38)
7. `routeMatchFn(pathname, request, Object.fromEntries(searchParams))` evaluates the pathname, request context, and query parameters against the compiled matcher rules. Sources: [packages/next/src/experimental/testing/server/middleware-testing-utils.ts:39](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testing/server/middleware-testing-utils.ts#L39)

> [!NOTE]
> If a middleware configuration omits the `matcher` property entirely, `unstable_doesMiddlewareMatch` defaults to returning `true` for any incoming URL and request combination.
> Sources: [packages/next/src/experimental/testing/server/middleware-testing-utils.ts:32-34](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testing/server/middleware-testing-utils.ts#L32-L34)

### Request Construction and Response Inspection Utilities

The testing suite provides helper utilities for generating request mocks and inspecting redirect or rewrite outcomes:

- `constructRequest()`: Normalizes incoming headers, automatically injects a `host` header derived from the URL if missing, and serializes a record of cookies into a semicolon-delimited `cookie` header string before instantiating a `NodeNextRequest` and `MockedRequest`. Sources: [packages/next/src/experimental/testing/server/utils.ts:8-32](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testing/server/utils.ts#L8-L32)
- `getRedirectUrl()`: Inspects a `NextResponse` and returns the value of the `location` header, or `null` if absent. Sources: [packages/next/src/experimental/testing/server/utils.ts:38-40](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testing/server/utils.ts#L38-L40)
- `isRewrite()`: Returns a boolean indicating whether the response contains a rewrite header. Sources: [packages/next/src/experimental/testing/server/utils.ts:46-48](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testing/server/utils.ts#L46-L48)
- `getRewrittenUrl()`: Returns the value of the `x-middleware-rewrite` header from a `NextResponse`, or `null` if not a rewrite. Sources: [packages/next/src/experimental/testing/server/utils.ts:54-56](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testing/server/utils.ts#L54-L56)

### Middleware Testing Configuration Interface

The types accepted by the middleware matcher evaluation function include the source configuration and matcher inputs:

| Property | Type | Description |
| :--- | :--- | :--- |
| `config` | `MiddlewareSourceConfig` | Object containing optional `matcher` definitions. Sources: [packages/next/src/experimental/testing/server/middleware-testing-utils.ts:9-11](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testing/server/middleware-testing-utils.ts#L9-L11) |
| `url` | `string` | The request URL to evaluate against matchers. Sources: [packages/next/src/experimental/testing/server/middleware-testing-utils.ts:25](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testing/server/middleware-testing-utils.ts#L25) |
| `headers` | `IncomingHttpHeaders` | Optional HTTP headers passed with the simulated request. Sources: [packages/next/src/experimental/testing/server/middleware-testing-utils.ts:28](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testing/server/middleware-testing-utils.ts#L28) |
| `cookies` | `Record<string, string>` | Optional key-value record of cookies serialized into request headers. Sources: [packages/next/src/experimental/testing/server/middleware-testing-utils.ts:29](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testing/server/middleware-testing-utils.ts#L29) |
| `nextConfig` | `NextConfig` | Optional Next.js configuration object. Sources: [packages/next/src/experimental/testing/server/middleware-testing-utils.ts:30](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testing/server/middleware-testing-utils.ts#L30) |

Sources: [packages/next/src/experimental/testing/server/middleware-testing-utils.ts:9-31](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testing/server/middleware-testing-utils.ts#L9-L31)

## Mock Request and Response Primitives

### Overview

Next.js provides in-memory streaming mock request and response primitives (`MockedRequest` and `MockedResponse`) to power server-side unit tests, routing suites, and internal rendering mechanisms without requiring a bound network socket or external HTTP server. These classes implement Node.js `Stream.Readable` and `Stream.Writable` interfaces alongside `IncomingMessage` and `ServerResponse` contracts.

Sources: [packages/next/src/server/lib/mock-request.ts:25-148](https://github.com/blade47/next.js/blob/main/packages/next/src/server/lib/mock-request.ts#L25-L148)

### Request Construction and Mocking API

The `constructRequest` utility function and the `createRequestResponseMocks` factory configure and instantiate these primitives for test execution. 

1. `constructRequest()` accepts an object containing a `url`, optional `headers`, and optional `cookies`. Sources: [packages/next/src/experimental/testing/server/utils.ts:8-16](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testing/server/utils.ts#L8-L16)
2. It ensures `headers` is initialized and automatically derives `headers.host` from the URL via `parseUrl(url)?.host` if not explicitly provided. Sources: [packages/next/src/experimental/testing/server/utils.ts:17-22](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testing/server/utils.ts#L17-L22)
3. If `cookies` are supplied as a record, it maps each entry to a `name=value` pair, joins them with semicolons, and sets `headers.cookie`. Sources: [packages/next/src/experimental/testing/server/utils.ts:23-30](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testing/server/utils.ts#L23-L30)
4. It instantiates a `MockedRequest` with the URL, headers, and method set to `'GET'`. Sources: [packages/next/src/experimental/testing/server/utils.ts:31](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testing/server/utils.ts#L31)
5. Finally, it wraps the `MockedRequest` inside a `NodeNextRequest` instance and returns it as a `BaseNextRequest`. Sources: [packages/next/src/experimental/testing/server/utils.ts:31](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testing/server/utils.ts#L31), [packages/next/src/server/lib/mock-request.ts:478-497](https://github.com/blade47/next.js/blob/main/packages/next/src/server/lib/mock-request.ts#L478-L497)

### Mock Options and Properties Reference

The configuration options accepted by `MockedRequest`, `MockedResponse`, and the overarching mock factory govern the behavior of the streaming primitives.

| Option / Property | Type | Default / Behavior | Description |
| :--- | :--- | :--- | :--- |
| `url` | `string` | Required | The request URL path and query string. Sources: [packages/next/src/server/lib/mock-request.ts:18](https://github.com/blade47/next.js/blob/main/packages/next/src/server/lib/mock-request.ts#L18) |
| `headers` | `IncomingHttpHeaders` | `{}` | Incoming HTTP request headers dictionary. Sources: [packages/next/src/server/lib/mock-request.ts:19](https://github.com/blade47/next.js/blob/main/packages/next/src/server/lib/mock-request.ts#L19) |
| `method` | `string` | `'GET'` | HTTP method for the request (e.g., `'GET'`, `'POST'`). Sources: [packages/next/src/server/lib/mock-request.ts:20](https://github.com/blade47/next.js/blob/main/packages/next/src/server/lib/mock-request.ts#L20) |
| `readable` | `Stream.Readable` | `undefined` | Optional upstream readable stream providing the request body. Sources: [packages/next/src/server/lib/mock-request.ts:21](https://github.com/blade47/next.js/blob/main/packages/next/src/server/lib/mock-request.ts#L21) |
| `socket` | `Socket \| null` | `null` | Underlying network socket proxy or null fallback. Sources: [packages/next/src/server/lib/mock-request.ts:22](https://github.com/blade47/next.js/blob/main/packages/next/src/server/lib/mock-request.ts#L22) |
| `statusCode` | `number` | `200` (for `MockedResponse`) | HTTP response status code. Sources: [packages/next/src/server/lib/mock-request.ts:141](https://github.com/blade47/next.js/blob/main/packages/next/src/server/lib/mock-request.ts#L141) |
| `maximumResponseBody` | `number` | `undefined` | Optional cap on captured response output buffer size. Sources: [packages/next/src/server/lib/mock-request.ts:145](https://github.com/blade47/next.js/blob/main/packages/next/src/server/lib/mock-request.ts#L145) |

Sources: [packages/next/src/server/lib/mock-request.ts:17-23](https://github.com/blade47/next.js/blob/main/packages/next/src/server/lib/mock-request.ts#L17-L23), [packages/next/src/server/lib/mock-request.ts:140-146](https://github.com/blade47/next.js/blob/main/packages/next/src/server/lib/mock-request.ts#L140-L146), [packages/next/src/server/lib/mock-request.ts:468-476](https://github.com/blade47/next.js/blob/main/packages/next/src/server/lib/mock-request.ts#L468-L476)

> [!WARNING]
> Unimplemented Node.js `IncomingMessage` or `ServerResponse` methods such as `aborted`, `complete`, `trailers`, and `setTimeout` throw a `Method not implemented` error when invoked on mock primitives. Ensure test code restricts its usage to supported streaming and property access APIs.
> Sources: [packages/next/src/server/lib/mock-request.ts:111-138](https://github.com/blade47/next.js/blob/main/packages/next/src/server/lib/mock-request.ts#L111-L138), [packages/next/src/server/lib/mock-request.ts:455-466](https://github.com/blade47/next.js/blob/main/packages/next/src/server/lib/mock-request.ts#L455-L466)

### Design Trade-Offs in Memory Mocking

| Design Choice | Benefit | Cost |
| :--- | :--- | :--- |
| Proxy-backed socket (`TLSSocket`) | Avoids instantiating full net/tls sockets while safely returning `encrypted: false` and `remoteAddress: undefined`. Sources: [packages/next/src/server/lib/mock-request.ts:39-53](https://github.com/blade47/next.js/blob/main/packages/next/src/server/lib/mock-request.ts#L39-L53) | Throws on access to any unmocked socket property. Sources: [packages/next/src/server/lib/mock-request.ts:42-46](https://github.com/blade47/next.js/blob/main/packages/next/src/server/lib/mock-request.ts#L42-L46) |
| In-memory buffer accumulation (`buffers` array) | Allows direct inspection of rendered output without disk or network I/O. Sources: [packages/next/src/server/lib/mock-request.ts:164-167](https://github.com/blade47/next.js/blob/main/packages/next/src/server/lib/mock-request.ts#L164-L167) | High memory overhead if response bodies are exceptionally large. Sources: [packages/next/src/server/lib/mock-request.ts:164-167](https://github.com/blade47/next.js/blob/main/packages/next/src/server/lib/mock-request.ts#L164-L167) |
| Manual stream proxying (`bodyReadable`) | Enables streaming request bodies seamlessly into server route handlers. Sources: [packages/next/src/server/lib/mock-request.ts:68-72](https://github.com/blade47/next.js/blob/main/packages/next/src/server/lib/mock-request.ts#L68-L72) | Requires explicit event forwarding for `end` and `close` streams. Sources: [packages/next/src/server/lib/mock-request.ts:68-72](https://github.com/blade47/next.js/blob/main/packages/next/src/server/lib/mock-request.ts#L68-L72) |

Sources: [packages/next/src/server/lib/mock-request.ts:39-77](https://github.com/blade47/next.js/blob/main/packages/next/src/server/lib/mock-request.ts#L39-L77), [packages/next/src/server/lib/mock-request.ts:162-168](https://github.com/blade47/next.js/blob/main/packages/next/src/server/lib/mock-request.ts#L162-L168)

## Testmode Request Interception and Context

### Overview

The testmode infrastructure in Next.js manages request context propagation and API interception across both Node.js and Edge runtimes. Using `AsyncLocalStorage`, request metadata containing test information is maintained throughout asynchronous execution flows. Request readers extract configuration and headers such as `next-test-proxy-port` and `next-test-data` to populate the `TestReqInfo` context store.

Sources: [packages/next/src/experimental/testmode/context.ts:1-28](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testmode/context.ts#L1-L28)

### Context Propagation and Request Readers

The context system defines the `TestRequestReader` interface for abstracting header extraction and URL retrieval across different request objects. Two distinct readers are implemented: one for standard `Request` objects in fetch/Edge contexts, and another for Node.js `IncomingMessage` instances.

| Reader Target | `url(req)` Implementation | `header(req, name)` Implementation |
| :--- | :--- | :--- |
| `Request` (Edge / Fetch) | `req.url` Sources: [packages/next/src/experimental/testmode/fetch.ts:12-15](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testmode/fetch.ts#L12-L15) | `req.headers.get(name)` Sources: [packages/next/src/experimental/testmode/fetch.ts:16-19](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testmode/fetch.ts#L16-L19) |
| `IncomingMessage` (Node.js) | `req.url ?? ''` Sources: [packages/next/src/experimental/testmode/server.ts:8-11](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testmode/server.ts#L8-L11) | Safely extracts string or array header values from `req.headers[name]` Sources: [packages/next/src/experimental/testmode/server.ts:12-22](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testmode/server.ts#L12-L22) |

Sources: [packages/next/src/experimental/testmode/fetch.ts:12-19](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testmode/fetch.ts#L12-L19), [packages/next/src/experimental/testmode/server.ts:8-22](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testmode/server.ts#L8-L22)

> [!NOTE]
> `getTestReqInfo` checks `AsyncLocalStorage` (`testStorage.getStore()`) first; if no store is active, it falls back to parsing headers directly from the provided request object using the supplied reader.
> Sources: [packages/next/src/experimental/testmode/context.ts:42-54](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testmode/context.ts#L42-L54)

### Interceptor Binding and Execution Flow

Global `fetch` calls and outbound HTTP requests are intercepted to route test operations through a local proxy daemon. In Node.js environments, `interceptTestApis` sets up both `interceptFetch` and `interceptHttpGet` (powered by `@mswjs/interceptors`), returning a combined cleanup function. Sources: [packages/next/src/experimental/testmode/server.ts:24-34](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testmode/server.ts#L24-L34)

The execution flow for an intercepted fetch request proceeds through the following call chain:
1. `testFetch(input, init)` intercepts global `fetch` invocations, ignoring requests marked with internal flags. Sources: [packages/next/src/experimental/testmode/fetch.ts:127-138](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testmode/fetch.ts#L127-L138)
2. `handleFetch(originalFetch, request)` calls `getTestInfo(request, reader)` to retrieve test context. Sources: [packages/next/src/experimental/testmode/fetch.ts:85-93](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testmode/fetch.ts#L85-L93)
3. If test info is present, `buildProxyRequest(testData, request)` constructs a `ProxyFetchRequest` payload containing serialized headers, method, body, and stack traces gathered via `getTestStack()`. Sources: [packages/next/src/experimental/testmode/fetch.ts:39-75](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testmode/fetch.ts#L39-L75), [packages/next/src/experimental/testmode/fetch.ts:95-96](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testmode/fetch.ts#L95-L96)
4. The request is dispatched via `originalFetch` to the local proxy port (`http://localhost:${proxyPort}`) as a POST payload. Sources: [packages/next/src/experimental/testmode/fetch.ts:98-105](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testmode/fetch.ts#L98-L105)
5. The proxy response JSON is evaluated by its `api` field (`continue`, `abort`, `unhandled`, or `fetch`), directing whether the original request is executed, an error is thrown, or a mocked response is built via `buildResponse()`. Sources: [packages/next/src/experimental/testmode/fetch.ts:110-124](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testmode/fetch.ts#L110-L124)

### Runtime Wrappers and Edge Integration

Both Node.js and Edge entry points provide request handler wrappers to ensure `AsyncLocalStorage` is correctly populated before handler execution. In Edge runtimes (`server-edge.ts`), `wrapRequestHandler` wraps request handlers with `withRequestContext`. In Node.js, worker and server request handlers (`wrapRequestHandlerWorker`, `wrapRequestHandlerNode`) bind incoming requests to `withRequest`.

Sources: [packages/next/src/experimental/testmode/server-edge.ts:8-12](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testmode/server-edge.ts#L8-L12), [packages/next/src/experimental/testmode/server.ts:36-47](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testmode/server.ts#L36-L47), [packages/next/src/server/web/adapter.ts:97-108](https://github.com/blade47/next.js/blob/main/packages/next/src/server/web/adapter.ts#L97-L108)

> [!WARNING]
> When `process.env.NEXT_PRIVATE_TEST_PROXY` is set to `'true'`, Edge route adapters automatically trigger `ensureTestApisIntercepted()`, activating test mode and wrapping OpenTelemetry context propagators with test request context bindings.
> Sources: [packages/next/src/server/web/adapter.ts:97-108](https://github.com/blade47/next.js/blob/main/packages/next/src/server/web/adapter.ts#L97-L108)

## Testmode Proxy Server and Fetching

### Overview

The testmode proxy server operates as an isolated local HTTP daemon (`http.createServer`) and fetching bridge that facilitates end-to-end test harnesses by intercepting and routing test API requests. It listens on an ephemeral loopback port (`::`) and coordinates with `FetchHandler` implementations to mock, continue, or abort outbound network operations.

Sources: [packages/next/src/experimental/testmode/proxy/server.ts:1-64](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testmode/proxy/server.ts#L1-L64), [packages/next/src/experimental/testmode/proxy/fetch-api.ts:1-15](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testmode/proxy/fetch-api.ts#L1-L15)

### Server Execution Walkthrough

When an incoming request hits the testmode proxy daemon, it flows through a strict parsing and dispatch sequence:
1. `readBody(req)` asynchronously aggregates incoming request stream chunks into a single `Buffer`. Sources: [packages/next/src/experimental/testmode/proxy/server.ts:8-16](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testmode/proxy/server.ts#L8-L16)
2. `JSON.parse(...)` decodes the buffer into a `ProxyRequest` payload; malformed payloads immediately receive a `400` status code and terminate. Sources: [packages/next/src/experimental/testmode/proxy/server.ts:30-37](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testmode/proxy/server.ts#L30-L37)
3. The server inspects the `json.api` discriminator field and dispatches to `handleFetch(json, onFetch)` when `api === 'fetch'`. Sources: [packages/next/src/experimental/testmode/proxy/server.ts:39-47](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testmode/proxy/server.ts#L39-L47)
4. `buildRequest(req)` reconstructs a standard `Request` object from the serialized headers and base64-encoded body, passing it along with `testData` to the registered `FetchHandler`. Sources: [packages/next/src/experimental/testmode/proxy/fetch-api.ts:16-24](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testmode/proxy/fetch-api.ts#L16-L24), [packages/next/src/experimental/testmode/proxy/fetch-api.ts:52-58](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testmode/proxy/fetch-api.ts#L52-L58)
5. `buildResponse(response)` translates the handler's `FetchHandlerResult` into a structured `ProxyResponse` object (`unhandled`, `abort`, `continue`, or a serialized `fetch` response containing status, base64 body, and headers). Sources: [packages/next/src/experimental/testmode/proxy/fetch-api.ts:26-50](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testmode/proxy/fetch-api.ts#L26-L50)
6. The resulting JSON payload is written back to the client with a `200` status code and `application/json` content type. Sources: [packages/next/src/experimental/testmode/proxy/server.ts:55-58](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testmode/proxy/server.ts#L55-L58)

### Proxy Server API and Types

The proxy module exports core factory functions and type definitions to manage proxy server instances and wire communication protocols between test harnesses and Next.js runtimes.

| Interface / Type | Members / Variants | Purpose |
| :--- | :--- | :--- |
| `ProxyServer` | `readonly port: number`, `fetchWith(input, init, testData)`, `close()` | Represents a running proxy instance, exposing its listening port, helper fetch wrapper, and shutdown hook. Sources: [packages/next/src/experimental/testmode/proxy/types.ts:1-9](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testmode/proxy/types.ts#L1-L9) |
| `ProxyRequest` | `ProxyFetchRequest` | Union type enclosing all serialized proxy request operations. Sources: [packages/next/src/experimental/testmode/proxy/types.ts:50](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testmode/proxy/types.ts#L50) |
| `ProxyResponse` | `ProxyUnhandledResponse`, `ProxyAbortResponse`, `ProxyContinueResponse`, `ProxyFetchResponse` | Union type defining outcomes returned by the proxy server or fetch handlers. Sources: [packages/next/src/experimental/testmode/proxy/types.ts:52-57](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testmode/proxy/types.ts#L52-L57) |
| `FetchHandlerResult` | `Response`, `'abort'`, `'continue'`, `null`, `undefined` | Possible return values permitted from custom `FetchHandler` implementations. Sources: [packages/next/src/experimental/testmode/proxy/fetch-api.ts:4-9](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testmode/proxy/fetch-api.ts#L4-L9) |

Sources: [packages/next/src/experimental/testmode/proxy/types.ts:1-60](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testmode/proxy/types.ts#L1-L60), [packages/next/src/experimental/testmode/proxy/fetch-api.ts:4-14](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testmode/proxy/fetch-api.ts#L4-L14)

> [!NOTE]
> The `fetchWith` method automatically populates the `Next-Test-Proxy-Port` header with the ephemeral port of the proxy daemon and the `Next-Test-Data` header with the supplied test data string before executing the underlying fetch request.
> Sources: [packages/next/src/experimental/testmode/proxy/server.ts:73-78](https://github.com/blade47/next.js/blob/main/packages/next/src/experimental/testmode/proxy/server.ts#L73-L78)

## Related

- [Test Runners](https://www.doc0.dev/docs/8f4009b0-65bd-4480-9b00-e201f0914bb3/technical/testing-infrastructure/test-runners)
- [Server Request Lifecycle](https://www.doc0.dev/docs/8f4009b0-65bd-4480-9b00-e201f0914bb3/technical/server-runtime/server-request-lifecycle)


## Sitemap

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