Relevant source files
The following files were used as context for generating this wiki page:
- packages/next/src/build/index.ts
- packages/next/taskfile.js
- packages/next/src/cli/next-build.ts
- packages/next/src/build/webpack-build/impl.ts
- packages/next/src/build/adapter/build-complete.ts
- packages/next/src/build/turbopack-build/impl.ts
- packages/next/src/build/utils.ts
- packages/next/src/build/type-check.ts
- packages/next/src/build/webpack-build/index.ts
- packages/next/src/bin/next.ts
- packages/next/src/build/compiler.ts
- packages/next/src/build/entries.ts
- packages/next/src/build/worker.ts
Overview
The build pipeline orchestrates the complete production compilation process for Next.js applications, transforming source files into optimized distribution bundles through CLI Commands, Route Discovery, and Turbopack Engine. It coordinates static code verification, multi-target compilation, static analysis worker tasks, and output finalization while supporting both Webpack and Turbopack Engine backends.
Sources: packages/next/src/build/index.ts:188-196, packages/next/src/cli/next-build.ts:6-19, packages/next/src/build/turbopack-build/impl.ts:25-30
Build Pipeline Lifecycle and Orchestration
Setup Tasks and Environment Initialization
The next build command initializes execution by loading exception listeners and environment configuration files via @next/env packages/next/src/build/index.ts:17-20. SWC bindings and lockfile patch promises are initialized alongside memory management checks for available write access and directory structures packages/next/src/build/index.ts:165-166. The build process installs required native compiler bindings, establishes tracing spans, and sets up global build contexts (NextBuildContext) before configuration loading packages/next/src/build/index.ts:166-189.
Sources: packages/next/src/build/index.ts:17-20, packages/next/src/build/index.ts:165-189
Convention File Detection and Route Discovery
Root convention files such as middleware, proxy configurations, and instrumentation hooks are discovered by scanning the root directory against standard regular expressions packages/next/src/build/index.ts:1469-1494. The build pipeline checks for deprecated Route Discovery patterns and prevents conflicting concurrent declarations, throwing an error if both middleware and proxy files exist simultaneously packages/next/src/build/index.ts:1521-1530.
Warning
Detecting both middleware and proxy filename conventions simultaneously at the root level throws an immediate build error. Applications must migrate exclusively to proxy using @next/codemod packages/next/src/build/index.ts:1521-1530.
Sources: packages/next/src/build/index.ts:1469-1494, packages/next/src/build/index.ts:1521-1530
Type Checking and Static Verification
Worker Execution and Implementation Selection
TypeScript setup and validation are delegated to a dedicated worker thread via verifyAndRunTypeScript, releasing compiler memory before compilation proceeds packages/next/src/build/type-check.ts:13-21. When type checking is enabled and the TypeScript CLI flag is inactive, the build pipeline instantiates a worker running verify-typescript-setup with exposed method verifyAndRunTypeScriptInWorker packages/next/src/build/type-check.ts:45-57. If useTypeScriptCli is enabled or checking is bypassed, execution falls back to in-process invocation packages/next/src/build/type-check.ts:58-64.
typeCheckWorker = new Worker(
require.resolve('../lib/verify-typescript-setup'),
{
exposedMethods: ['verifyAndRunTypeScriptInWorker'],
debuggerPortOffset: -1,
isolatedMemory: false,
numWorkers: 1,
enableWorkerThreads,
maxRetries: 0,
}
) as typeof typeCheckWorkerSources: packages/next/src/build/type-check.ts:46-56
Caution
If a worker call encounters retry exhaustion (Call retries were exceeded), the build flushes telemetry and terminates with process.exit(1) rather than propagating internal Jest worker errors packages/next/src/build/type-check.ts:185-193.
Sources: packages/next/src/build/type-check.ts:185-193
Lifecycle and Telemetry Reporting
The startTypeChecking routine orchestrates the verification span (run-typescript), tracking check duration and reporting telemetry metrics upon completion packages/next/src/build/type-check.ts:96-184.
| Parameter / Metric | Source Field | Purpose |
|---|---|---|
durationInSeconds | typeCheckEnd[0] | Duration of the type checking span in seconds |
typescriptVersion | verifyResult.version | Resolved TypeScript compiler version |
inputFilesCount | verifyResult.result?.inputFilesCount | Number of input files processed by the checker |
totalFilesCount | verifyResult.result?.totalFilesCount | Total file count in the TypeScript project program |
incremental | verifyResult.result?.incremental | Whether incremental compilation was utilized |
typeCheckMode | verifyResult.typeCheckMode | Active mode utilized for type verification |
Sources: packages/next/src/build/type-check.ts:173-183
Entrypoint Creation and Route Mapping
Compiler Entrypoint Generation and Mappings
The build pipeline creates compiler entrypoints by executing createEntrypoints, which processes mapped app paths, root paths, and pages to populate Webpack EntryObject tables for the client, server, and edgeServer compilers packages/next/src/build/entries.ts:388-411. Before processing individual page handlers, createEntrypoints normalizes catch-all routes and validates route matching coherence across appPathsPerRoute packages/next/src/build/entries.ts:418-435. When config.experimental.strictRouteMatching is enabled, the pipeline checks for missing canonical interception routes, incompatible parallel route slots, and unmatched app pages, throwing consolidated route-matching errors if inconsistencies are detected packages/next/src/build/entries.ts:451-526.
const missingCanonicalInterceptionRoutes = config.experimental
.strictRouteMatching
? findMissingCanonicalInterceptionRoutes(appPagePathsPerRoute)
: []
const routeMatchingErrors: Error[] = []
if (missingCanonicalInterceptionRoutes.length > 0) {
routeMatchingErrors.push(
new MissingCanonicalInterceptionRoutesError(
missingCanonicalInterceptionRoutes
)
)
}
if (incompatibleParallelRouteSlots.length > 0) {
routeMatchingErrors.push(
new IncompatibleParallelRouteSlotsError(
await Promise.all(
incompatibleParallelRouteSlots.map(async (incompatibleRoute) => {
const layoutPagePath = posix.join(
incompatibleRoute.layoutPath,
'layout'
)
const layoutFile = await findPageFile(
appDir,
layoutPagePath,
pageExtensions,
true
)
return {
...incompatibleRoute,
layoutFile: relative(
rootDir,
layoutFile
? join(appDir, layoutFile)
: join(appDir, layoutPagePath)
),
}
})
)
)
)
}
if (unmatchedAppPages.length > 0) {
routeMatchingErrors.push(
new UnmatchedAppPagesError(
unmatchedAppPages.map((appPath) => {
const absolutePagePath = appPageFiles.get(appPath)
if (!absolutePagePath) return appPath
return relative(
rootDir,
getPageFilePath({
absolutePagePath,
pagesDir,
appDir,
rootDir,
})
)
})
)
)
}
if (routeMatchingErrors.length > 0) {
const warning = getStrictRouteMatchingDefaultWarning(config)
if (warning) {
Log.warnOnce(warning)
}
}
if (routeMatchingErrors.length === 1) {
throw routeMatchingErrors[0]
}
if (routeMatchingErrors.length > 1) {
throw new Error(
routeMatchingErrors.map((error) => error.message).join('\n\n')
)
}Sources: packages/next/src/build/entries.ts:451-526
Warning
Mismatched parallel route slots or missing canonical interception routes during strict route matching will cause the build pipeline to throw validation errors immediately before entrypoints are compiled packages/next/src/build/entries.ts:451-526.
Sources: packages/next/src/build/entries.ts:451-526
Runtime Selection and Loader Routing
The runtime target and loader configuration for a given page are determined by evaluating file types, runtimes, and page types through runDependingOnPageType and specific builder helpers packages/next/src/build/entries.ts:322-386. Depending on whether a route belongs to the Pages router, App router, API route handlers, instrumentation hooks, or middleware, the pipeline selects the appropriate compilation strategy.
| Page / File Type | Condition | Target Runtimes / Handlers |
|---|---|---|
| Root Instrumentation Hook | pageType === PAGE_TYPES.ROOT && isInstrumentationHookFile(page) | Server and Edge Server packages/next/src/build/entries.ts:330-337 |
| Proxy File | isProxyFile(page) | Server (Node.js) packages/next/src/build/entries.ts:339-342 |
| Middleware File | isMiddlewareFile(page) | Server (if nodejs runtime) or Edge Server packages/next/src/build/entries.ts:344-352 |
| API Route | isAPIRoute(page) | Edge Server (if Edge runtime) or Server packages/next/src/build/entries.ts:354-362 |
| Document Page | page === '/_document' | Server (Node.js) packages/next/src/build/entries.ts:363-366 |
Core App Pages (_app, _error, 404, 500) | page === '/_app' || page === '/_error' || page === '/404' || page === '/500' | Client and Server packages/next/src/build/entries.ts:367-376 |
| Edge Runtime Page | isEdgeRuntime(pageRuntime) | Client and Edge Server packages/next/src/build/entries.ts:377-381 |
Sources: packages/next/src/build/entries.ts:322-386
Tip
When edgeServer.instrumentation is the sole entry in the edge server object, the build pipeline removes the redundant edge instrumentation entry since instrumentation can execute purely on the Node.js server packages/next/src/build/entries.ts:798-803.
Sources: packages/next/src/build/entries.ts:798-803
Entrypoint Finalization and Webpack Layers
Once initial entry objects are assembled, finalizeEntrypoint assigns the required webpack configuration layers (layer), runtimes (runtime), and chunking parameters based on the active compilerType (server, edgeServer, or client) packages/next/src/build/entries.ts:813-915. For server-side entries, API routes are assigned WEBPACK_LAYERS.apiNode, instrumentation hooks map to WEBPACK_LAYERS.instrument, and React Server Components map to WEBPACK_LAYERS.reactServerComponents packages/next/src/build/entries.ts:835-852. Edge server entries are configured with EDGE_RUNTIME_WEBPACK runtime, assignment library structures (_ENTRIES), and disabled async chunks (asyncChunks: false) packages/next/src/build/entries.ts:853-867. Client entries configure dependency relationships (dependOn) pointing to runtime chunks such as CLIENT_STATIC_FILES_RUNTIME_MAIN or CLIENT_STATIC_FILES_RUNTIME_MAIN_APP packages/next/src/build/entries.ts:868-911.
switch (compilerType) {
case COMPILER_NAMES.server: {
const layer = isApi
? WEBPACK_LAYERS.apiNode
: isInstrumentation
? WEBPACK_LAYERS.instrument
: isServerComponent
? WEBPACK_LAYERS.reactServerComponents
: name.startsWith('pages/')
? WEBPACK_LAYERS.pagesDirNode
: undefined
return {
publicPath: isApi ? '' : undefined,
runtime: isApi ? 'webpack-api-runtime' : 'webpack-runtime',
layer,
...entry,
}
}
case COMPILER_NAMES.edgeServer: {
return {
layer: isApi
? WEBPACK_LAYERS.apiEdge
: isMiddlewareFilename(name) || isInstrumentation
? WEBPACK_LAYERS.middleware
: name.startsWith('pages/')
? WEBPACK_LAYERS.pagesDirEdge
: undefined,
library: { name: ['_ENTRIES', `middleware_[name]`], type: 'assign' },
runtime: EDGE_RUNTIME_WEBPACK,
asyncChunks: false,
...entry,
}
}Sources: packages/next/src/build/entries.ts:834-867
Webpack Production Compilation Execution
Worker-Dispatched Compilation and Sequencing
Production bundling delegates compilation tasks to isolated worker threads or executes them synchronously based on configuration flags packages/next/src/build/webpack-build/index.ts:131-163. When worker isolation is enabled via webpackBuildWithWorker, the build pipeline processes compilers sequentially in a predefined order: server, edge-server, and client packages/next/src/build/webpack-build/index.ts:14-18, packages/next/src/build/webpack-build/index.ts:34-121. Each compiler runs inside a separate worker process initialized with serialized build contexts, trace states, and telemetry instances packages/next/src/build/webpack-build/impl.ts:405-437.
Sources: packages/next/src/build/webpack-build/impl.ts:246-299, packages/next/src/build/webpack-build/index.ts:34-121
Warning
Server compilers must execute before the client compiler so that client component boundaries discovered during server rendering are injected into the client entry configuration via pluginState.injectedClientEntries packages/next/src/build/webpack-build/impl.ts:232-288.
Sources: packages/next/src/build/webpack-build/impl.ts:232-288
Compiler Execution and Lifecycle Handling
The low-level compiler runner initializes the bundler via getWebpackBundler(), preserves file system caching instances (inputFileSystem), tracks fsStartTime, and guarantees that compilers are properly closed upon completion packages/next/src/build/compiler.ts:39-92.
| Function / Helper | File Path | Purpose |
|---|---|---|
runCompiler | packages/next/src/build/compiler.ts | Executes a Webpack configuration, manages file system bindings, and coordinates compiler closure packages/next/src/build/compiler.ts:39-92 |
closeCompiler | packages/next/src/build/compiler.ts | Invokes Webpack 5 compiler.close() to flush persistent caches packages/next/src/build/compiler.ts:32-37 |
generateStats | packages/next/src/build/compiler.ts | Extracts errors, warnings, and module traces from compilation stats objects packages/next/src/build/compiler.ts:11-28 |
webpackBuildImpl | packages/next/src/build/webpack-build/impl.ts | Orchestrates entry point generation, compiler runs, message formatting, and error throwing packages/next/src/build/webpack-build/impl.ts:73-402 |
Sources: packages/next/src/build/compiler.ts:11-92, packages/next/src/build/webpack-build/impl.ts:73-402]
Note
Webpack 5 requires compilers to be explicitly closed to persist filesystem and memory caches correctly; closeCompiler checks for the presence of the close method for backwards compatibility packages/next/src/build/compiler.ts:30-37.
Sources: packages/next/src/build/compiler.ts:30-37
Error Formatting and Fatal Exit Codes
Post-compilation messages are formatted using formatWebpackMessages, and error thresholds determine whether the build terminates or proceeds packages/next/src/build/webpack-build/impl.ts:324-401. If errors are encountered, the builder truncates output lists exceeding 5 entries to minimize noise and scans messages for specific diagnostic conditions packages/next/src/build/webpack-build/impl.ts:338-377.
if (
error.indexOf('private-next-pages') > -1 &&
error.indexOf('does not contain a default export') > -1
) {
const page_name_regex = /'private-next-pages\/(?<page_name>[^']*)'/
const parsed = page_name_regex.exec(error)
const page_name = parsed && parsed.groups && parsed.groups.page_name
throw new Error(
`webpack build failed: found page without a React Component as default export in pages/${page_name}\n\nSee https://nextjs.org/docs/messages/page-without-valid-component for more info.`
)
}
console.error(error)
console.error()
if (
error.indexOf('private-next-pages') > -1 ||
error.indexOf('__next_polyfill__') > -1
) {
const err = new Error(
'webpack config.resolve.alias was incorrectly overridden. https://nextjs.org/docs/messages/invalid-resolve-alias'
) as NextError
err.code = 'INVALID_RESOLVE_ALIAS'
throw err
}
const err = new Error(
`Build failed because of ${process.env.NEXT_RSPACK ? 'Rspack' : 'webpack'} errors`
) as NextError
err.code = 'WEBPACK_ERRORS'
throw errSources: packages/next/src/build/webpack-build/impl.ts:348-377
Static Analysis and Worker Tasks
Worker Environment Initialization and Task Dispatch
Next.js offloads heavy static analysis tasks, such as determining page static rendering properties, to isolated worker threads via packages/next/src/build/worker.ts. Before executing static analysis operations, the worker entry point configures the runtime environment by establishing the global client asset suffix for Turbopack compiled code using process.env.__NEXT_PRERENDER_CLIENT_ASSET_SUFFIX.
// Set the global asset suffix for Turbopack compiled code to use during prerendering
;(globalThis as any).NEXT_CLIENT_ASSET_SUFFIX =
process.env.__NEXT_PRERENDER_CLIENT_ASSET_SUFFIX
Sources: packages/next/src/build/worker.ts:9-12
Note
Native SWC bindings and code-frame support are installed explicitly inside the worker entry module rather than inside utility modules. This prevents devtools code-frame renderers from leaking into production server file traces while ensuring that errors thrown during static analysis render structured code frames.
Sources: packages/next/src/build/worker.ts:14-20
Worker-Dispatched Utility Exports
The worker thread acts as an execution boundary exposing specialized static verification and export handlers to the master build orchestrator.
| Exported Handler / Function | Source File | Purpose |
|---|---|---|
isPageStatic | packages/next/src/build/worker.ts | Installs SWC bindings and code frame support asynchronously before delegating to isPageStaticImpl |
getDefinedNamedExports | packages/next/src/build/worker.ts | Re-exports module analysis utilities for identifying named exports from code |
hasCustomGetInitialProps | packages/next/src/build/worker.ts | Re-exports page component inspection helpers to detect custom data fetching methods |
exportPages | packages/next/src/build/worker.ts | Dispatches export page worker tasks for static generation |
Sources: packages/next/src/build/worker.ts:13-27
Post Build Manifest Processing
Adapter Output Finalization and Route Fields
The build pipeline finalizes production artifacts by constructing structured metadata objects for routing adapters, server runtimes, and deployment platforms. Each entry point generated during compilation maps to shared route fields that capture asset boundaries, runtime environments, and segment configurations.
interface SharedRouteFields {
/**
* id is the unique identifier of the output
*/
id: string
/**
* filePath is the location on disk of the built entrypoint asset
*/
filePath: string
/**
* pathname is the URL pathname the asset should be served at
*/
pathname: string
/**
* sourcePage is the original source in the app or pages folder
*/
sourcePage: string
/**
* runtime is which runtime the entrypoint is built for
*/
runtime: 'nodejs' | 'edge'
/**
* assets are all necessary traced assets that could be
* loaded by the output to handle a request e.g. traced
* node_modules or necessary manifests for Next.js.
* The key is the relative path from the repo root
*/
assets: Record<string, string>
/**
* Hashes of the contents of each `assets` entry (not including the output path!)
*/
assetsHashes: Record<string, string>
/**
* wasmAssets are bundled wasm files. The key is the (opaque) name of asset
*/
wasmAssets?: Record<string, string>
/**
* edgeRuntime contains canonical entry metadata for invoking
* this output in an edge runtime.
*/
edgeRuntime?: {
/**
* modulePath is the canonical module path that registers this
* output in the edge runtime.
*/
modulePath: string
/**
* entryKey is the canonical key used for the global edge entry registry.
*/
entryKey: string
/**
* handlerExport is the export name to invoke on the edge entry.
*/
handlerExport: string
}
/**
* config related to the route
*/
config: {
/**
* maxDuration is a segment config to signal the max
* execution duration a route should be allowed before
* it's timed out
*/
maxDuration?: number
/**
* preferredRegion is a segment config to signal deployment
* region preferences to the provider being used
*/
preferredRegion?: string | string[]
/**
* env is the environment variables to expose, this is onlySources: packages/next/src/build/adapter/build-complete.ts:73-157
App paths sharing an identical URL pathname are collapsed into a single adapter output using orderAppPageKeysByEntry, which selects the canonical entry page to anchor merged asset tracking.
function orderAppPageKeysByEntry(appPageKeys: readonly string[]): string[] {
const appPathsByPathname = new Map<string, string[]>()
for (const page of appPageKeys) {
const pathname = normalizeAppPath(page)
const appPaths = appPathsByPathname.get(pathname)
if (appPaths) {
appPaths.push(page)
} else {
appPathsByPathname.set(pathname, [page])
}
}
const orderedAppPageKeys: string[] = []
for (const [pathname, appPaths] of appPathsByPathname) {
const entryPage = selectAppPageEntry(pathname, appPaths)
orderedAppPageKeys.push(entryPage)
for (const appPath of appPaths) {Sources: packages/next/src/build/adapter/build-complete.ts:212-231
Prerender groups classify their primary responses through specific classification dimensions, separating non-UI routes, page shells, and full prerender outputs.
| Property | Allowed Values / Types | Meaning |
|---|---|---|
routeType | 'route' | 'fallback' | 'shell' | 'page' | Canonical response category (non-UI route, partial fallback, page shell, or complete page) |
response | 'empty' | 'initial' | 'complete' | Completeness of the response prior to request-time work |
compute | 'blocking' | 'resuming' | 'static' | Request-time compute required to serve the completed response |
htmlSize | number (optional) | Byte size of the prerendered HTML shell |
Sources: packages/next/src/build/adapter/build-complete.ts:163-208
NFT File Tracing and Asset Mapping
Node File Tracing (NFT) processes emitted build artifacts to discover runtime dependencies, native bindings, and required configuration files. The build pipeline maps NFT file entries into asset records and computes content hashes for individual tracked files to ensure deployment bundles include every necessary module without extraneous files.
import { mapNftFileEntries, type NftJson } from '../nft'Sources: packages/next/src/build/adapter/build-complete.ts:65-65
Note
Asset hash records track file contents explicitly across all traced dependencies (assetsHashes) to detect modifications between build and deployment phases without re-hashing output bundle files themselves.
Sources: packages/next/src/build/adapter/build-complete.ts:106-108
Build-Complete Hooks and Telemetry Dispatch
Upon finishing all compilation stages, route discovery, and manifest serialization, the orchestrator triggers build-complete hooks and records build statistics via telemetry events. Success and failure states emit distinct events (eventBuildCompleted and eventBuildFailed) along with performance timings, feature usage analytics, and diagnostic metadata updates.
eventBuildCompleted,
eventBuildFailed,Sources: packages/next/src/build/index.ts:120-121
Related
On This Page
OverviewBuild Pipeline Lifecycle and OrchestrationSetup Tasks and Environment InitializationConvention File Detection and Route DiscoveryType Checking and Static VerificationWorker Execution and Implementation SelectionLifecycle and Telemetry ReportingEntrypoint Creation and Route MappingCompiler Entrypoint Generation and MappingsRuntime Selection and Loader RoutingEntrypoint Finalization and Webpack LayersWebpack Production Compilation ExecutionWorker-Dispatched Compilation and SequencingCompiler Execution and Lifecycle HandlingError Formatting and Fatal Exit CodesStatic Analysis and Worker TasksWorker Environment Initialization and Task DispatchWorker-Dispatched Utility ExportsPost Build Manifest ProcessingAdapter Output Finalization and Route FieldsNFT File Tracing and Asset MappingBuild-Complete Hooks and Telemetry DispatchRelated