Relevant source files
The following files were used as context for generating this wiki page:
- packages/next/src/build/turbopack-build/impl.ts
- packages/next/src/build/index.ts
- packages/next/src/shared/lib/turbopack/manifest-loader.ts
- packages/next/src/server/dev/hot-reloader-turbopack.ts
- packages/next/src/server/dev/turbopack-utils.ts
- packages/next/taskfile.js
- packages/next/src/client/next-turbopack.ts
- packages/next/src/build/adapter/build-complete.ts
- packages/next/src/build/webpack/plugins/next-trace-entrypoints-plugin.ts
- packages/next/src/build/webpack-build/impl.ts
- packages/next/src/build/handle-entrypoints.ts
- packages/next/src/client/route-loader.ts
- packages/next/src/build/swc/index.ts
- packages/next/src/build/webpack/plugins/flight-manifest-plugin.ts
- packages/next/src/build/turbopack-analyze/index.ts
- packages/next/src/server/load-manifest.external.ts
- packages/next/src/client/app-next-turbopack.ts
- packages/next/src/build/turbopack-build/index.ts
- packages/next/src/build/webpack/plugins/flight-client-entry-plugin.ts
- packages/next/src/build/webpack/plugins/middleware-plugin.ts
- packages/next/src/cli/next-post-build.ts
- packages/next/src/client/next-dev-turbopack.ts
- packages/next/src/build/utils.ts
- packages/next/src/build/turborepo-access-trace/result.ts
- packages/next/src/build/duration-to-string.ts
- packages/next/src/lib/turbopack-warning.ts
- packages/next/src/server/config.ts
Overview
The Turbopack engine coordinates high-performance compilation, route processing, manifest loading, and telemetry workflows within Next.js. Built on Rust-based SWC Compiler bindings, it manages production builds via Build Pipeline invocations and processes dynamic project entrypoints into typed endpoints.
Sources: packages/next/src/build/turbopack-build/impl.ts:48-56, packages/next/src/build/turbopack-build/index.ts:1-12
The engine bridges low-level SWC operations with high-level routing structures, utilizing TurbopackManifestLoader data structures for atomic manifest merging and disk writes. It provisions client runtime entrypoints, handles configuration validation against unsupported options, and executes diagnostic workflows for bundle analysis.
Sources: packages/next/src/build/turbopack-build/impl.ts:227-234, packages/next/src/shared/lib/turbopack/manifest-loader.ts:181-210, packages/next/src/lib/turbopack-warning.ts:41-47
Turbopack Production Build Invocation
Build Lifecycle and Span Coordination
Production compilation begins when the build pipeline invokes turbopackBuild, wrapping execution inside a traced child span (run-turbopack) derived from NextBuildContext.nextBuildSpan. The underlying implementation turbopackBuildImpl coordinates configuration validation, native binding verification, and project compilation stages before returning timing metadata and a shutdown promise.
Sources: packages/next/src/build/turbopack-build/impl.ts:25-34, packages/next/src/build/turbopack-build/index.ts:5-12
Warning
Turbopack requires native SWC bindings. If bindings.isWasm is true, execution throws an immediate error demanding fallback to Webpack via next build --webpack because WebAssembly bindings are unsupported for production builds.
Sources: packages/next/src/build/turbopack-build/impl.ts:50-58
Lifecycle Execution Stages
The production compilation pipeline executes a strict sequence of validation, event monitoring, error reporting, and disk output generation.
Upon successful compilation checks, the engine initializes compilation event background logging, validates project errors using printBuildErrors, writes a turbopack signal file alongside a CommonJS package.json into the distribution directory, and flushes all entrypoints and route manifests to disk.
Sources: packages/next/src/build/turbopack-build/impl.ts:149-194, packages/next/src/build/turbopack-build/impl.ts:227-296
Entrypoint Resolution and Route Processing
Raw Entrypoint Normalization
The build engine transforms raw project entrypoints returned by the Rust bindings into categorized, typed route maps via rawEntrypointsToEntrypoints. This routine iterates over entrypointsOp.routes and dispatches each route based on its route.type discriminant, populating separate Maps for pages and app routes while preserving global singleton endpoints.
| Route Type Discriminant | Target Collection / Action | Source Reference |
|---|---|---|
page / page-api | Added to page Map via page.set(pathname, route) | packages/next/src/build/handle-entrypoints.ts:18-22 |
app-page | Iterates over route.pages, adding to app Map via p.originalName | packages/next/src/build/handle-entrypoints.ts:23-31 |
app-route | Added to app Map via route.originalName | packages/next/src/build/handle-entrypoints.ts:32-35 |
conflict | Logs an informational message via Log.info skipping the route | packages/next/src/build/handle-entrypoints.ts:36-38 |
Sources: packages/next/src/build/handle-entrypoints.ts:11-42
Warning
When encountering a conflict route type during raw entrypoint conversion, Turbopack skips the pathname entirely rather than throwing an error, logging the skipped route via Log.info.
Sources: packages/next/src/build/handle-entrypoints.ts:36-38
Route Type Handling and Manifest Loading
Once raw entrypoints are normalized, turbopackBuild iterates through the resulting page and app maps, passing each entry to handleRouteType alongside a TurbopackManifestLoader instance. This function executes route-specific manifest loading routines determined by the exact route variant.
For page entries, the loader requests client build manifests, build manifests, pages manifests, middleware manifests (deleting the entry's middleware key if the manifest was not written), font manifests for /_app and the page itself, and SRI manifests. For app-page entries, it loads middleware manifests, build manifests, app paths manifests, action manifests, font manifests, and SRI manifests.
Sources: packages/next/src/build/handle-entrypoints.ts:67-116
Note
If manifestLoader.loadMiddlewareManifest returns falsy (indicating no middleware file was generated for that route), handleRouteType explicitly calls manifestLoader.deleteMiddlewareManifest using the server entry key computed by getEntryKey.
Sources: packages/next/src/build/handle-entrypoints.ts:74-78, packages/next/src/build/handle-entrypoints.ts:91-95, packages/next/src/build/handle-entrypoints.ts:102-106, packages/next/src/build/handle-entrypoints.ts:130-132
Incremental Manifest Loader Architecture
Manifest Path Resolution and External Loaders
The incremental manifest loader architecture centers around TurbopackManifestLoader and its internal ManifestsMap data structures. ManifestsMap encapsulates a dual-map structure maintaining both raw string representations (rawMap) and parsed JavaScript values (map), while tracking whether entries have changed since the last disk serialization. This design prevents redundant serialization and unnecessary disk I/O during incremental compilation.
Sources: packages/next/src/shared/lib/turbopack/manifest-loader.ts:182-199
Note
ManifestsMap.set compares incoming JSON string values against rawMap. If the serialized string matches an existing entry, changed remains untouched, bypassing downstream updates.
Sources: packages/next/src/shared/lib/turbopack/manifest-loader.ts:140-145
Manifest file paths are dynamically resolved via getManifestPath, which calculates target directories under distDir/server/type, factoring in route normalization, metadata routes, and sitemap variants. Complementing build-time generation, external utilities like loadManifest and evalManifest handle runtime or build-time manifest consumption from the file system, incorporating optional in-memory caching and deep-freezing (deepFreeze) to safeguard cached objects against modification.
Tip
When resolving manifest paths for /sitemap or /sitemap.xml routes, getManifestPath uses existsSync to check alternate path variants and metadata ID suffixes before finalizing the disk path.
Sources: packages/next/src/shared/lib/turbopack/manifest-loader.ts:71-118, packages/next/src/server/load-manifest.external.ts:21-77
Client Runtime Entrypoints for Turbopack
Browser Bootstrap and Initialization
Next.js provides distinct entrypoints for initializing Turbopack client applications across production pages, App Router bundles, and development HMR environments. Each entrypoint registers deployment IDs globally, configures window.next, initializes __next_set_public_path__ and __webpack_hash__, and orchestrates chunk loading.
| Client Script File | Target Environment | Key Bootstrap Action | Sources |
|---|---|---|---|
next-turbopack.ts | Production Pages | Calls initialize({}), sets up __turbopack_load_page_chunks__, and invokes hydrate() | packages/next/src/client/next-turbopack.ts:1-45 |
app-next-turbopack.ts | App Router (Prod/Dev) | Executes appBootstrap with app-index hydration and optional dev overlay | packages/next/src/client/app-next-turbopack.ts:1-29 |
next-dev-turbopack.ts | Development Pages | Initializes HMR client via initHMR(), connects WebSocket messaging, and calls pageBootstrap(assetPrefix) | packages/next/src/client/next-dev-turbopack.ts:1-59 |
Sources: packages/next/src/client/next-turbopack.ts:1-45, packages/next/src/client/app-next-turbopack.ts:1-29, packages/next/src/client/next-dev-turbopack.ts:1-59
Note
In both production and development page entrypoints, __turbopack_load_page_chunks__ maps over chunk identifiers using __turbopack_load__(c) and catches failures via Promise.all.
Sources: packages/next/src/client/next-turbopack.ts:28-39, packages/next/src/client/next-dev-turbopack.ts:32-43
Development HMR and App Overlay Integration
The development runtime establishes communication channels with the Turbopack hot reloader by binding message listeners, update error handlers, and global chunk update listeners.
connect({
addMessageListener(cb: (message: TurbopackMessageSentToBrowser) => void) {
devClient.addTurbopackMessageListener(cb)
},
sendMessage: devClient.sendTurbopackMessage,
onUpdateError: devClient.handleUpdateError,
chunkUpdateListenersGlobal:
process.env.__NEXT_TURBOPACK_CHUNK_UPDATE_LISTENERS_GLOBAL!,
})Sources: packages/next/src/client/next-dev-turbopack.ts:45-53
Tip
App Router development builds in app-next-turbopack.ts evaluate process.env.__NEXT_DEV_SERVER to conditionally attach the error overlay with owner stacks, recoverable error callbacks, and cache indicators.
Sources: packages/next/src/client/app-next-turbopack.ts:16-28
Turbopack Configuration and Validation
Configuration Validation and Unsupported Options
Next.js validates next.config.js via validateTurboNextConfig during production builds to detect unsupported compiler or experimental options that Turbopack does not yet recognize. It flattens all user-provided configuration keys, compares them against defaultConfig, and evaluates them against an explicit list of unsupported options stored in unsupportedTurbopackNextConfigOptions.
const unsupportedTurbopackNextConfigOptions = [
// Left to be implemented (priority)
// 'experimental.clientRouterFilter',
// 'experimental.optimizePackageImports',
// 'compiler.emotion',
// 'compiler.reactRemoveProperties',
// 'compiler.relay',
// 'compiler.removeConsole',
// 'compiler.styledComponents',
'experimental.fetchCacheKeyPrefix',
// Left to be implemented
// 'excludeDefaultMomentLocales',
// 'experimental.optimizeServerReact',
'experimental.clientRouterFilterAllowedRate',
// 'experimental.serverMinification',
// 'experimental.serverSourceMaps',
'experimental.allowedRevalidateHeaderKeys',
'experimental.extensionAlias',
'experimental.fallbackNodePolyfills',
'experimental.swcTraceProfiling',
// Left to be implemented (Might not be needed for Turbopack)
'experimental.craCompat',
'experimental.disablePostcssPresetEnv',
'experimental.esmExternals',
// This is used to force swc-loader to run regardless of finding Babel.
'experimental.forceSwcTransforms',
'experimental.fullySpecified',
'experimental.urlImports',
'experimental.slowModuleDetection',
]Sources: packages/next/src/lib/turbopack-warning.ts:5-38
Warning
If a user specifies options such as experimental.fetchCacheKeyPrefix, experimental.extensionAlias, experimental.fallbackNodePolyfills, or experimental.swcTraceProfiling alongside Turbopack, the validation engine flags them as unsupported, logs an error listing each invalid option, and guides developers to the documentation.
Sources: packages/next/src/lib/turbopack-warning.ts:14-28, packages/next/src/lib/turbopack-warning.ts:169-187
Default Webpack Configuration Detection and Migration Warnings
When TURBOPACK environment mode is set to 'auto', the validator checks whether a custom webpack configuration is present without a corresponding turbopack configuration block. If found, it halts execution with an error urging migration or explicit flag setting.
if (process.env.TURBOPACK === 'auto' && hasWebpackConfig && !hasTurboConfig) {
const configFile = rawNextConfig.configFileName ?? 'your Next config file'
Log.error(
`ERROR: This build is using Turbopack, with a \`webpack\` config and no \`turbopack\` config.
This may be a mistake.
As of Next.js 16 Turbopack is enabled by default and
custom webpack configurations may need to be migrated to Turbopack.
NOTE: your \`webpack\` config may have been added by a configuration plugin.
To configure Turbopack, see https://nextjs.org/docs/app/api-reference/next-config-js/turbopack
TIP: Many applications work fine under Turbopack with no configuration,
if that is the case for you, you can silence this error by passing the
\`--turbopack\` or \`--webpack\` flag explicitly or simply setting an
empty turbopack config in ${configFile} (e.g. \`turbopack: {}\`).`
)
process.exit(1)
}Sources: packages/next/src/lib/turbopack-warning.ts:146-166
Tip
Developers can silence the auto-mode webpack configuration error by passing --turbopack or --webpack explicitly, or by adding an empty turbopack: {} configuration block to their Next.js config file.
Sources: packages/next/src/lib/turbopack-warning.ts:159-163
Server Configuration Normalization and Bundler Constraints
The assignDefaultsAndValidate function in packages/next/src/server/config.ts enforces strict constraints on bundler-specific settings, memory eviction strategies, and persistent caching directories during initialization.
| Configuration Field / Option | Validation Rule / Normalization Target | Sources |
|---|---|---|
distDir | Throws an error if set to 'public' or an empty string "" | packages/next/src/server/config.ts:387-401 |
sassOptions.functions | Throws an error if customized when running under Turbopack | packages/next/src/server/config.ts:566-576 |
experimental.cssChunking | Resolves mode ('graph' requires Turbopack; 'strict' and false require Webpack) | packages/next/src/server/config.ts:603-624 |
turbopack.chunkLoadingGlobal | Automatically prefixes global chunk names with TURBOPACK_ if missing | packages/next/src/server/config.ts:1226-1231 |
Sources: packages/next/src/server/config.ts:387-401, packages/next/src/server/config.ts:566-576, packages/next/src/server/config.ts:603-624, packages/next/src/server/config.ts:1226-1231
Bundle Analysis and Compilation Diagnostics
Turbopack Analyze Workflow and Execution
The turbopackAnalyze function orchestrates an analysis-only production build context to capture compilation metrics, dependencies, and bundle layouts. It validates the configuration against PHASE_PRODUCTION_BUILD, loads native bindings via loadBindings, detects supported browsers, and instantiates a Turbopack project with persistentCaching enabled or disabled according to config.experimental?.turbopackFileSystemCacheForBuild.
export async function turbopackAnalyze(
analyzeContext: AnalyzeContext
): Promise<{
duration: number
shutdownPromise: Promise<void>
}> {
await validateTurboNextConfig({
dir: analyzeContext.dir,
configPhase: PHASE_PRODUCTION_BUILD,
})
const { config, dir, distDir, noMangling } = analyzeContext
const currentNodeJsVersion = process.versions.node
const startTime = process.hrtime()
const bindings = await loadBindings(config?.experimental?.useWasmBinary)
if (bindings.isWasm) {
throw new Error(
`Turbopack analyze is not supported on this platform (${process.platform}/${process.arch}) because native bindings are not available. ` +
`Only WebAssembly (WASM) bindings were loaded, and Turbopack requires native bindings.\n\n` +
`For more information, see: https://nextjs.org/docs/app/api-reference/turbopack#supported-platforms`
)
}
const dev = false
const supportedBrowsers = getSupportedBrowsers(dir, dev)
const persistentCaching =
config.experimental?.turbopackFileSystemCacheForBuild || false
const rootPath = config.turbopack?.root || config.outputFileTracingRoot || dir
const projectResult = await bindings.turbo.createProject(
{
rootPath: config.turbopack?.root || config.outputFileTracingRoot || dir,
projectPath: normalizePath(path.relative(rootPath, dir) || '.'),
distDir,
nextConfig: config,
watch: {
enable: false,
},
dev,
env: process.env as Record<string, string>,
defineEnv: createDefineEnv({
isTurbopack: true,
config,
dev,
distDir,
projectPath: dir,
fetchCacheKeyPrefix: config.experimental.fetchCacheKeyPrefix,
hasRewrites: false,
// Implemented separately in Turbopack, doesn't have to be passed here.
middlewareMatchers: undefined,
rewrites: {
beforeFiles: [],
afterFiles: [],
fallback: [],
},
}),
buildId: 'analyze-build',
encryptionKey: '',
previewProps: {
previewModeId: '',
previewModeEncryptionKey: '',
previewModeSigningKey: '',
},
browserslistQuery: supportedBrowsers.join(', '),
noMangling,
writeRoutesHashesManifest: false,
currentNodeJsVersion,
isPersistentCachingEnabled: persistentCaching,
nextVersion: process.env.__NEXT_VERSION as string,
},
{
turbopackMemoryEviction: config.experimental.turbopackMemoryEvictionMode,
gc: config.experimental.turbopackGcOptions,
dependencyTracking: persistentCaching,
isCi: isCI,
isShortSession: true,
}Sources: packages/next/src/build/turbopack-analyze/index.ts:23-103
| Project Creation Option | Value / Source | Sources |
|---|---|---|
rootPath | `config.turbopack?.root | |
projectPath | `normalizePath(path.relative(rootPath, dir) | |
watch.enable | false | packages/next/src/build/turbopack-analyze/index.ts:61-63 |
buildId | 'analyze-build' | packages/next/src/build/turbopack-analyze/index.ts:82-82 |
isPersistentCachingEnabled | persistentCaching | packages/next/src/build/turbopack-analyze/index.ts:93-93 |
turbopackMemoryEviction | config.experimental.turbopackMemoryEvictionMode | packages/next/src/build/turbopack-analyze/index.ts:97-97 |
gc | config.experimental.turbopackGcOptions | packages/next/src/build/turbopack-analyze/index.ts:98-98 |
Sources: packages/next/src/build/turbopack-analyze/index.ts:54-102
Caution
Turbopack analyze requires native binary bindings and will throw an immediate error if only WebAssembly (WASM) bindings are loaded on the current platform and architecture (process.platform/process.arch).
Sources: packages/next/src/build/turbopack-analyze/index.ts:40-46
Compilation Event Telemetry and Issue Handling
During production builds (turbopackBuild) and analysis (turbopackAnalyze), Turbopack hooks into background compilation events using backgroundLogCompilationEvents. This attaches a tracing span (NextBuildContext.nextBuildSpan or turbopack-analyze-events) to capture granular telemetry such as persistence updates and compaction trace spans.
const compilationEvents = backgroundLogCompilationEvents(project, {
// Compilation events carry their own timestamps, so they hang directly off
// the build rather than a synthetic grouping span.
parentSpan: NextBuildContext.nextBuildSpan,
signal: shutdownController.signal,
})Sources: packages/next/src/build/turbopack-build/impl.ts:149-154, packages/next/src/build/turbopack-analyze/index.ts:108-113
Note
Project shutdown triggers a cleanup sequence that awaits both project.shutdown() and the resolution of compilationEvents, protected by a 10-second unref timeout backstop to guarantee that compilation telemetry and database persistence traces are fully flushed.
Sources: packages/next/src/build/turbopack-build/impl.ts:155-167
When persistent caching and build compaction are enabled, post-build workflows execute database compaction against the Turbopack cache database.
const bindings = await loadBindings(config.experimental?.useWasmBinary)
await bindings.turbo.databaseCompact(
cachePath,
process.env.__NEXT_VERSION as string
)
console.log('Turbopack database compaction complete.')Sources: packages/next/src/cli/next-post-build.ts:42-47
Related
On This Page
OverviewTurbopack Production Build InvocationBuild Lifecycle and Span CoordinationLifecycle Execution StagesEntrypoint Resolution and Route ProcessingRaw Entrypoint NormalizationRoute Type Handling and Manifest LoadingIncremental Manifest Loader ArchitectureManifest Path Resolution and External LoadersClient Runtime Entrypoints for TurbopackBrowser Bootstrap and InitializationDevelopment HMR and App Overlay IntegrationTurbopack Configuration and ValidationConfiguration Validation and Unsupported OptionsDefault Webpack Configuration Detection and Migration WarningsServer Configuration Normalization and Bundler ConstraintsBundle Analysis and Compilation DiagnosticsTurbopack Analyze Workflow and ExecutionCompilation Event Telemetry and Issue HandlingRelated