Relevant source files
The following files were used as context for generating this wiki page:
- packages/next/src/server/base-server.ts
- packages/next/src/server/next-server.ts
- packages/next-routing/src/resolve-routes.ts
- packages/next/src/server/lib/router-server.ts
- packages/next/src/build/templates/app-route.ts
- packages/next/src/build/templates/app-page-runtime.ts
- packages/next/src/server/lib/router-utils/resolve-routes.ts
- packages/next/src/server/dev/next-dev-server.ts
- packages/next/src/server/web/adapter.ts
- packages/next/src/build/templates/edge-ssr-app.ts
- packages/next/src/build/templates/pages-api.ts
- packages/next/src/server/route-modules/app-route/module.ts
- packages/next/src/server/normalizers/built/app/app-bundle-path-normalizer.ts
- packages/next/src/server/normalizers/built/pages/pages-bundle-path-normalizer.ts
- packages/next/src/server/request-meta.ts
- packages/next/src/server/send-payload.ts
- packages/next/src/build/duration-to-string.ts
- packages/next/src/server/config.ts
Overview
The request lifecycle orchestrates how HTTP requests are received, parsed, routed, and fulfilled across both Node.js and Edge Runtime environments. It manages request metadata propagation via Async Storage, matches incoming paths against custom routes, headers, and redirects, and normalizes bundle paths for App and Pages directories. The pipeline controls the execution of Server Components, Route Handlers, and legacy Pages APIs while interfacing with the Incremental Cache to dispatch optimized payloads and responses.
Sources: packages/next/src/server/base-server.ts:1071-1080, packages/next/src/server/web/adapter.ts:127-145, packages/next/src/server/request-meta.ts:51-175, packages/next-routing/src/resolve-routes.ts:557-600, packages/next/src/server/normalizers/built/app/app-bundle-path-normalizer.ts:7-15, packages/next/src/server/normalizers/built/pages/pages-bundle-path-normalizer.ts:7-21, packages/next/src/build/templates/app-page-runtime.ts:245-280, packages/next/src/build/templates/pages-api.ts:47-80, packages/next/src/server/send-payload.ts:35-50
Edge and Server Request Metadata
Request Metadata Operations
Per-request metadata tracking in Next.js relies on a shared internal symbol NEXT_REQUEST_META (Symbol.for('NextInternalRequestMeta')) attached directly to incoming message objects (NextIncomingMessage), bridging Node.js HTTP requests, base HTTP wrappers, and Web API request types.
Sources: packages/next/src/server/request-meta.ts:19-27
During request execution, the invocation path passes through specific middleware handling routines. In handleCatchallMiddlewareRequest(), the server checks whether the request has an active middleware invocation flag. When middleware is absent or routing matchers evaluate to false, handleFinished() is invoked. Inside handleFinished(), the call chain invokes addRequestMeta(req, 'middlewareInvoke', true) to record the completed state, which in turn calls getRequestMeta() to read the existing metadata dictionary before setting the key. The full call sequence is handleCatchallMiddlewareRequest → handleFinished → addRequestMeta → getRequestMeta.
Sources: packages/next/src/server/next-server.ts:1943-2053, packages/next/src/server/request-meta.ts:421-429, packages/next/src/server/request-meta.ts:393-399
Sources: packages/next/src/server/next-server.ts:1943-2053, packages/next/src/server/request-meta.ts:421-429, packages/next/src/server/request-meta.ts:393-399
Metadata Fields and Structure
The RequestMeta interface maintains state regarding routing decisions, incremental caching layers, locale negotiation, and development diagnostics.
| Field | Type | Purpose |
|---|---|---|
initQuery | ParsedUrlQuery | The initial query string parameters used to make the request. |
initURL | string | The full request URL string captured at entry. |
initProtocol | string | The protocol scheme (http or https) associated with the request. |
clonableBody | CloneableBody | Multi-readable request body stream wrapper. |
isLocaleDomain | boolean | True when the request matches a configured locale domain. |
didStripLocale | boolean | True when locale information was stripped from the URL pathname. |
rewrittenPathname | string | The target pathname if the request URL underwent a rewrite. |
middlewareCookie | string[] | Cookies added by middleware to be appended to the response. |
match | RouteMatch | The resolved route match object for the current pathname. |
incrementalCache | IncrementalCache | The incremental cache provider instance assigned to the request. |
serverComponentsHmrCache | ServerComponentsHmrCache | Development-only HMR cache for server components. |
hmrRefreshHash | string | Hash of the latest server component change used in "use cache" keys. |
segmentPrefetchRSCRequest | string | Target segment path for prefetch RSC requests. |
isPrefetchRSCRequest | true | True when the request fetches prefetch flight data. |
isRSCRequest | true | True when the request fetches React Server Component flight data. |
cacheBustingSearchParam | string | Search param hash verifying custom headers to prevent cache poisoning on CDNs. |
isNextDataReq | true | True when requesting /_next/data via the Pages Router. |
postponed | string | Postponed PPR state string used for resumption rendering. |
actionBody | Buffer | Action payload extracted from server action requests. |
onCacheEntry | OnCacheEntryHandler | Deprecated callback invoked on response cache hits or generations. |
onCacheEntryV2 | OnCacheEntryHandler | Callback invoked when a response cache entry is generated or retrieved. |
notFoundRevalidate | number | false | Revalidation interval prior to rendering a 404 page for notFound: true. |
developmentNotFoundSourcePage | string | Original source page returning a 404 during development. |
invokePath | string | Internal routing invocation path. |
invokeOutput | string | Specific page output target for matching. |
invokeStatus | number | Status code passed during internal routing invocation. |
invokeError | Error | Routing error object associated with an invocation. |
invokeQuery | Record<string, ...> | Parsed query parameters for internal routing invocations. |
middlewareInvoke | boolean | Flag indicating whether the request is a middleware invocation. |
renderFallbackShell | boolean | True if the server should render the fallback shell. |
resolvedRouteParamKeys | Set<string> | Route parameter keys explicitly resolved from partial query parameters. |
customErrorRender | true | True when rendering the custom application error page. |
bubbleNoFallback | true | Bubble NoFallbackError to the caller when a 404 occurs. |
localeInferredFromDefault | true | True when the locale was inferred from the default configuration. |
locale | string | The active locale set or inferred for the request. |
defaultLocale | string | The default locale configured for the application. |
relativeProjectDir | string | Relative path of the project directory from the root. |
distDir | string | Build output distribution directory. |
hostname | string | Hostname used by route handlers for absolute URL construction. |
revalidate | RevalidateFn | Internal revalidation function bypassing network calls. |
render404 | Function | Callback rendering the Pages Router 404 page. |
query | ParsedUrlQuery | Resolved query parameters after route matching. |
params | ParsedUrlQuery | Resolved dynamic route parameters after route matching. |
PagesErrorDebug | PagesDevOverlayBridgeType | Error overlay component bridge for the Pages Router in development. |
minimalMode | boolean | True when running the server in minimal resource mode. |
stagedFallbackParams | OpaqueFallbackRouteParams | Route params deferred until after the static stage in PPR. |
fallbackRouteParams | OpaqueFallbackRouteParams | Route params substituted with opaque placeholders during shell debugging. |
devParamMatchingRejected | boolean | Development flag indicating parameter matching rejection. |
devNotFoundParams | readonly string[] | Closed parameters including allowed values in development. |
devRequestTimingStart | bigint | Request start timestamp in nanoseconds via process.hrtime.bigint(). |
devRequestTimingMiddlewareStart | bigint | Middleware execution start timestamp in development. |
devRequestTimingMiddlewareEnd | bigint | Middleware execution completion timestamp in development. |
devRequestTimingInternalsEnd | bigint | Internal processing completion timestamp in development. |
devGenerateStaticParamsDuration | bigint | Duration of getStaticPaths or generateStaticParams execution. |
devServerActionLog | object | Server action execution logs captured in development. |
Sources: packages/next/src/server/request-meta.ts:51-375
Note
The NEXT_REQUEST_META symbol allows mutable request attributes to persist across framework boundaries, including Node.js IncomingMessage, custom BaseNextRequest wrappers, and Web NextRequest abstractions, preventing metadata loss during internal request forwarding and middleware runs.
Sources: packages/next/src/server/request-meta.ts:18-27
Route Resolution and Header Rewriting
Path Matching and Internationalization
Incoming HTTP requests undergo initial route resolution through resolveRoutes, which evaluates request URLs, normalizes _next/data requests when shouldNormalizeNextData is enabled, and applies internationalization (i18n) locale detection. When i18n is configured and the request does not target _next or api paths, the system inspects cookies, accept-language headers, pathnames, and domain configuration.
// Handle i18n locale detection and redirects
if (i18n && !isDataUrl) {
const pathname = currentUrl.pathname.startsWith(basePath)
? currentUrl.pathname.slice(basePath.length) || '/'
: currentUrl.pathname
// Skip locale handling for _next and api routes
if (!pathname.startsWith('/_next/') && !pathname.startsWith('/api/')) {
const hostname = currentUrl.hostname
const cookieHeader = currentRequestHeaders.get('cookie') || undefined
const acceptLanguageHeader =
currentRequestHeaders.get('accept-language') || undefined
// Detect locale from path first
const pathLocaleResult = normalizeLocalePath(pathname, i18n.locales)
const localeInPath = !!pathLocaleResult.detectedLocale
// Detect domain locale
const domainLocale = detectDomainLocale(i18n.domains, hostname)
const defaultLocale = domainLocale?.defaultLocale || i18n.defaultLocale
// Determine target locale if locale detection is enabled
let targetLocale = pathLocaleResult.detectedLocale || defaultLocale
// Match Next.js behavior: preferred-locale auto-detection redirects only
// on index requests, not on arbitrary non-locale pathnames.
const shouldDetectPreferredLocale =
i18n.localeDetection !== false &&
!localeInPath &&
pathLocaleResult.pathname === '/'
if (shouldDetectPreferredLocale) {
const detectedResult = detectLocale({
pathname,
hostname,
cookieHeader,
acceptLanguageHeader,
i18n,
})
targetLocale = detectedResult.localeSources: packages/next-routing/src/resolve-routes.ts:602-643
If preferred-locale auto-detection triggers on root index requests without an explicit path locale, the request redirects to the detected locale or domain. Otherwise, the locale is prefixed internally for route resolution without triggering an HTTP redirect.
Tip
Preferred-locale auto-detection is restricted strictly to root index requests (pathLocaleResult.pathname === '/') when no explicit locale exists in the path, preventing unexpected redirects on nested application routes.
Sources: packages/next-routing/src/resolve-routes.ts:628-632
Middleware Execution and Header Overrides
After processing beforeMiddleware rules, the routing engine evaluates whether the request matches any middleware matchers. If matched, middleware is invoked, and any resulting headers, redirects, or rewrites are applied to the request and response objects.
const middlewareHeaders = toNodeOutgoingHttpHeaders(
middlewareRes.headers
) as Record<string, string | string[] | undefined>
debug('middleware res', middlewareRes.status, middlewareHeaders)
if (middlewareHeaders['x-middleware-override-headers']) {
const overriddenHeaders: Set<string> = new Set()
let overrideHeaders: string | string[] =
middlewareHeaders['x-middleware-override-headers']
if (typeof overrideHeaders === 'string') {
overrideHeaders = overrideHeaders.split(',')
}
for (const key of overrideHeaders) {
overriddenHeaders.add(key.trim())
}
delete middlewareHeaders['x-middleware-override-headers']
// Delete headers.
for (const key of Object.keys(req.headers)) {
if (!overriddenHeaders.has(key)) {
delete req.headers[key]
}
}
// Update or add headers.
for (const key of overriddenHeaders.keys()) {
const valueKey = 'x-middleware-request-' + key
const newValue = middlewareHeaders[valueKey]
const oldValue = req.headers[key]
if (oldValue !== newValue) {
req.headers[key] = newValue === null ? undefined : newValue
}
delete middlewareHeaders[valueKey]
}
}Sources: packages/next/src/server/lib/router-utils/resolve-routes.ts:662-700
When middleware returns x-middleware-override-headers, the server parses the specified header names, strips unlisted incoming request headers, and applies new values prefixed with x-middleware-request-. Headers explicitly blocked by ipcForbiddenHeaders or control keys such as content-length, x-middleware-rewrite, x-middleware-redirect, and x-middleware-refresh are filtered out or handled specially.
Caution
The x-middleware-set-cookie header is assigned directly to request headers (req.headers['x-middleware-set-cookie'] = value) rather than copied to response headers, ensuring cookies passed from middleware persist for downstream request processing.
Sources: packages/next/src/server/lib/router-utils/resolve-routes.ts:725-730
Dynamic Routes and Condition Evaluation
Once file system checks and beforeFiles rewrites complete, dynamic routes are scanned against pathnames and query conditions using has and missing parameters.
for (const route of routes.dynamicRoutes) {
const match = matchDynamicRoute(currentUrl.pathname, route, caseSensitive)
if (!match.matched) {
continue
}
const hasResult = checkHasConditions(
route.has,
currentUrl,
currentRequestHeaders
)
const missingMatched = checkMissingConditions(
route.missing,
currentUrl,
currentRequestHeaders
)
if (!hasResult.matched || !missingMatched) {
continue
}Sources: packages/next-routing/src/resolve-routes.ts:881-901
If a dynamic route matches both pattern criteria and validation conditions, its destination is resolved via query merging and matched headers from routes.onMatch are appended to the response context.
Path Normalization and Manifest Mapping
App Router Normalizers
The App Router utilizes specialized normalizers to transform route strings and filenames into canonical bundle paths. The AppBundlePathNormalizer extends PrefixingNormalizer with an 'app' prefix, applying normalizePagePath to convert pages into their normalized pathname representations.
Sources: packages/next/src/server/normalizers/built/app/app-bundle-path-normalizer.ts:7-15
In development mode, DevAppBundlePathNormalizer orchestrates a composite normalizer chain via Normalizers. It combines the incoming page normalizer and an AppBundlePathNormalizer, conditionally prepending an UnderscoreNormalizer when Turbopack is active to handle %5F to _ replacements.
Sources: packages/next/src/server/normalizers/built/app/app-bundle-path-normalizer.ts:17-31
Note
The %5F to _ underscore replacement in bundle paths is restricted strictly to Turbopack compilation runs within DevAppBundlePathNormalizer.
Sources: packages/next/src/server/normalizers/built/app/app-bundle-path-normalizer.ts:26-29
Pages Router Normalizers
For the legacy Pages Router, PagesBundlePathNormalizer wraps normalizePagePath to strip trailing /index segments from bundle paths before passing them through a PrefixingNormalizer initialized with the 'pages' prefix.
Sources: packages/next/src/server/normalizers/built/pages/pages-bundle-path-normalizer.ts:7-16
The corresponding development variant, DevPagesBundlePathNormalizer, composes the pages-specific normalizer with a runtime page normalizer to translate filenames into target route paths during on-demand compilation.
Sources: packages/next/src/server/normalizers/built/pages/pages-bundle-path-normalizer.ts:23-31
| Normalizer Class | Base Class / Wrapper | Prefix / Target | Core Operation |
|---|---|---|---|
AppBundlePathNormalizer | PrefixingNormalizer | 'app' | Normalizes page paths via normalizePagePath and prefixes with 'app' |
DevAppBundlePathNormalizer | Normalizers | 'app' (+ optional UnderscoreNormalizer) | Combines page normalizer, app normalizer, and conditional Turbopack underscore normalization |
PagesBundlePathNormalizer | Normalizers | 'pages' | Strips trailing /index via normalizePagePath and prefixes with 'pages' |
DevPagesBundlePathNormalizer | Normalizers | 'pages' | Chains pages file normalizer with PagesBundlePathNormalizer |
Sources: packages/next/src/server/normalizers/built/app/app-bundle-path-normalizer.ts:7-31, packages/next/src/server/normalizers/built/pages/pages-bundle-path-normalizer.ts:7-31
App Page Runtime Execution Pipeline
Runtime Template Invocation and Handler Initialization
The App Page runtime execution pipeline begins when incoming requests are processed by generated runtime templates such as packages/next/src/build/templates/app-page-runtime.ts and Edge SSR templates like packages/next/src/build/templates/edge-ssr-app.ts. The main handler function extracts request metadata, normalizes source paths via normalizeAppPath, and parses dynamic route segment parameter names from the route pattern.
Sources: packages/next/src/build/templates/app-page-runtime.ts:206-222
async function handler(
req: IncomingMessage,
res: ServerResponse,
ctx: {
waitUntil?: (prom: Promise<void>) => void
requestMeta?: RequestMeta
}
) {
if (ctx.requestMeta) {
setRequestMeta(req, ctx.requestMeta)
}Sources: packages/next/src/build/templates/app-page-runtime.ts:215-225
Requests are prepared via routeModule.prepare, evaluating multi-zone draft mode configuration and returning a comprehensive context object containing build manifests, router contexts, query parameters, and configuration properties.
Sources: packages/next/src/build/templates/app-page-runtime.ts:245-280
Warning
Failing to capture req.url into httpTarget before routeModule.prepare runs will cause subsequent CDN URL rewrites to corrupt trace span attributes.
Sources: packages/next/src/build/templates/app-page-runtime.ts:236-241
PPR Resumption and Server Actions Handling
When Partial Prerendering (PPR) is enabled via nextConfig.cacheComponents, incoming requests accompanied by postponed resume state headers undergo body size and limit validations. If NEXT_RESUME_STATE_LENGTH_HEADER is present alongside a server action request, the runtime reads the request body with a combined size budget comprising the state length and action body limit.
Sources: packages/next/src/build/templates/app-page-runtime.ts:349-390
const resumeStateLengthHeader = req.headers[NEXT_RESUME_STATE_LENGTH_HEADER]
if (
!getRequestMeta(req, 'postponed') &&
isMinimalMode &&
couldSupportPPR &&
isPossibleServerAction &&
resumeStateLengthHeader &&
typeof resumeStateLengthHeader === 'string'
) {
const stateLength = parseInt(resumeStateLengthHeader, 10)
const { maxPostponedStateSize, maxPostponedStateSizeBytes } =
getMaxPostponedStateSize(nextConfig.experimental.maxPostponedStateSize)
if (!isNaN(stateLength) && stateLength > 0) {
if (stateLength > maxPostponedStateSizeBytes) {
res.statusCode = 413
res.end(getPostponedStateExceededErrorMessage(maxPostponedStateSize))
ctx.waitUntil?.(Promise.resolve())
return null
}Sources: packages/next/src/build/templates/app-page-runtime.ts:353-372
The raw request buffer is subdivided into the postponed state string—stored in request metadata under 'postponed'—and the remaining action body payload destined for the server action handler.
Sources: packages/next/src/build/templates/app-page-runtime.ts:403-411
Route Invocation and Edge SSR Adapters
Route modules execute rendering operations by wrapping Node request and response objects into NodeNextRequest and NodeNextResponse adapters, dispatching either routeModule.prerender or routeModule.render depending on the active render operation.
Sources: packages/next/src/build/templates/app-page-runtime.ts:777-789
const invokeRouteModule = async (
span: Span | undefined,
context: AppPageRouteHandlerContext,
renderOperation: AppPageRenderOperation
) => {
const nextReq = new NodeNextRequest(req)
const nextRes = new NodeNextResponse(res)
const result =
renderOperation === 'prerender'
? routeModule.prerender(nextReq, nextRes, context)
: routeModule.render(nextReq, nextRes, context)
return result.finally(() => {Sources: packages/next/src/build/templates/app-page-runtime.ts:777-790
In Edge SSR runtime templates, renderResultToResponse converts render outcomes into standard Web Response instances, setting appropriate x-edge-runtime headers, mapping fetch metrics, and piping dynamic readable streams via TransformStream.
Sources: packages/next/src/build/templates/edge-ssr-app.ts:250-328
| Operation Context | Target Parameter / Header | Default / Fallback Value | Purpose |
|---|---|---|---|
| Action Body Limit | nextConfig.experimental.serverActions?.bodySizeLimit | '1 MB' (1024 * 1024 bytes) | Bounded payload size check for server action requests |
| Postponed State Size | nextConfig.experimental.maxPostponedStateSize | Platform default limits | Validates incoming PPR postponed state length against configuration |
| Response Content-Type | result.contentType | 'text/html; charset=utf-8' | Establishes mime type for Edge SSR responses |
| Edge Runtime Header | 'x-edge-runtime' | '1' | Identifies responses originating from the V8 edge sandbox |
Sources: packages/next/src/build/templates/app-page-runtime.ts:378-387, packages/next/src/build/templates/edge-ssr-app.ts:272-274
Pages API Template Request Processing
Request Preparation and Route Module Initialization
The legacy Pages API handler initializes by accepting incoming IncomingMessage and ServerResponse objects alongside a context object containing optional waitUntil and requestMeta properties. If requestMeta is provided, it is attached to the request, and development timing metrics are recorded if routeModule.isDev is active. For Turbopack environments, dynamic route page paths ending in /index are normalized to ensure correct path matching.
Sources: packages/next/src/build/templates/pages-api.ts:47-68
const prepareResult = await routeModule.prepare(req, res, { srcPage })
if (!prepareResult) {
res.statusCode = 400
res.end('Bad Request')
ctx.waitUntil?.(Promise.resolve())
return
}Sources: packages/next/src/build/templates/pages-api.ts:70-77
Warning
If routeModule.prepare returns a falsy result, the response status code is immediately set to 400 with a "Bad Request" body, short-circuiting execution before any userland route module rendering occurs.
Sources: packages/next/src/build/templates/pages-api.ts:72-77
Tracing Context and Route Execution
When preparation succeeds, the request method and active OpenTelemetry tracer are retrieved to establish distributed tracing spans. Depending on whether the server wraps the request, the handler either uses an existing active span or initiates a new BaseServerSpan.handleRequest trace with server span kinds and route attributes.
Sources: packages/next/src/build/templates/pages-api.ts:79-92, packages/next/src/build/templates/pages-api.ts:172-196
const invokeRouteModule = async (span?: Span) =>
routeModule
.render(req, res, {
query: {
...query,
...params,
},
params,
allowedRevalidateHeaderKeys: process.env
.__NEXT_ALLOWED_REVALIDATE_HEADERS as any as string[],
multiZoneDraftMode: Boolean(process.env.__NEXT_MULTI_ZONE_DRAFT_MODE),
trustHostHeader: process.env
.__NEXT_TRUST_HOST_HEADER as any as boolean,
// TODO: get this from from runtime env so manifest
// doesn't need to load
previewProps,
propagateError: false,
dev: routeModule.isDev,
page: 'VAR_DEFINITION_PAGE',
internalRevalidate: routerServerContext?.revalidate,
onError: (...args: Parameters<InstrumentationOnRequestError>) =>
onRequestError(req, ...args),
})Sources: packages/next/src/build/templates/pages-api.ts:93-117
Spans are finalized via .finally() hooks that inspect res.statusCode. Status codes of 500 or greater trigger SpanStatusCode.ERROR along with error.type attributes. Root span attributes are verified to match BaseServerSpan.handleRequest before updating trace span names with HTTP methods and matched route paths.
Sources: packages/next/src/build/templates/pages-api.ts:118-170
Error Boundary Traps and Response Delivery
Uncaught exceptions thrown during route module invocation are intercepted by a catch block. In development mode, errors are re-thrown directly to trigger the error overlay. In production environments, an internal server error is dispatched using sendError, serving a 500 status response.
Sources: packages/next/src/build/templates/pages-api.ts:197-205
} finally {
// We don't allow any waitUntil work in pages API routes currently
// so if callback is present return with resolved promise since no
// pending work
ctx.waitUntil?.(Promise.resolve())
}Sources: packages/next/src/build/templates/pages-api.ts:205-210
Note
Pages API routes do not currently permit asynchronous background work via waitUntil, so the finally block immediately resolves any pending waitUntil promise callbacks.
Sources: packages/next/src/build/templates/pages-api.ts:206-210
Response Payload Dispatch and Caching
ETag Validation and Caching Headers
The payload dispatch pipeline verifies response state and sets caching and metadata headers before outputting content. If a response has already been sent, execution returns immediately. When poweredByHeader is enabled and the response content type matches the HTML content type header, the X-Powered-By: Next.js header is assigned.
Sources: packages/next/src/server/send-payload.ts:35-56
// If cache control is already set on the response we don't
// override it to allow users to customize it via next.config
if (cacheControl && !res.getHeader('Cache-Control')) {
res.setHeader('Cache-Control', getCacheControlHeader(cacheControl))
}
const payload = result.isDynamic ? null : result.toUnchunkedString()
if (generateEtags && payload !== null) {
const etag = generateETag(payload)
if (sendEtagResponse(req, res, etag)) {
return
}
}Sources: packages/next/src/server/send-payload.ts:58-71
Cache control headers are populated using getCacheControlHeader if not already present, preserving user customizations set via next.config. For unchunked static payloads, ETags are generated and evaluated via sendEtagResponse. If the request headers match the generated ETag using fresh, status 304 is assigned, the connection is ended, and dispatch terminates early.
Sources: packages/next/src/server/send-payload.ts:11-33, packages/next/src/server/send-payload.ts:58-71
Warning
When generating a 304 Not Modified response, the server sets required validation headers such as ETag per RFC 7232 before ending the response without a body.
Sources: packages/next/src/server/send-payload.ts:16-24
Payload Streaming and Node Response Piping
if (!res.getHeader('Content-Type') && result.contentType) {
res.setHeader('Content-Type', result.contentType)
}
if (payload) {
res.setHeader('Content-Length', Buffer.byteLength(payload))
}
if (req.method === 'HEAD') {
res.end(null)
return
}
if (payload !== null) {
res.end(payload)
return
}
// Pipe the render result to the response after we get a writer for it.
await result.pipeToNodeResponse(res)Sources: packages/next/src/server/send-payload.ts:73-92
Content type and content length headers are registered for non-empty payloads. If the incoming method is HEAD, the body is omitted and the response is terminated. Unchunked string payloads are dispatched directly via res.end(payload), whereas dynamic streaming results are piped to the underlying Node response using result.pipeToNodeResponse(res).
Sources: packages/next/src/server/send-payload.ts:73-92
Related
On This Page
OverviewEdge and Server Request MetadataRequest Metadata OperationsMetadata Fields and StructureRoute Resolution and Header RewritingPath Matching and InternationalizationMiddleware Execution and Header OverridesDynamic Routes and Condition EvaluationPath Normalization and Manifest MappingApp Router NormalizersPages Router NormalizersApp Page Runtime Execution PipelineRuntime Template Invocation and Handler InitializationPPR Resumption and Server Actions HandlingRoute Invocation and Edge SSR AdaptersPages API Template Request ProcessingRequest Preparation and Route Module InitializationTracing Context and Route ExecutionError Boundary Traps and Response DeliveryResponse Payload Dispatch and CachingETag Validation and Caching HeadersPayload Streaming and Node Response PipingRelated