Skip to main content
doc0blade47/next.jsdocumentation home
Sign in

Turbopack Engine

Last updated Oct 12, 2026100% grounded
Relevant source files

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

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 DiscriminantTarget Collection / ActionSource Reference
page / page-apiAdded to page Map via page.set(pathname, route)packages/next/src/build/handle-entrypoints.ts:18-22
app-pageIterates over route.pages, adding to app Map via p.originalNamepackages/next/src/build/handle-entrypoints.ts:23-31
app-routeAdded to app Map via route.originalNamepackages/next/src/build/handle-entrypoints.ts:32-35
conflictLogs an informational message via Log.info skipping the routepackages/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.

Internal Map PropertyValue Type / TargetSource Reference
actionManifestsManifestsMap<EntryKey, ActionManifest>packages/next/src/shared/lib/turbopack/manifest-loader.ts:182-183
appPathsManifestsManifestsMap<EntryKey, PagesManifest>packages/next/src/shared/lib/turbopack/manifest-loader.ts:184-185
buildManifestsManifestsMap<EntryKey, BuildManifest>packages/next/src/shared/lib/turbopack/manifest-loader.ts:186-187
clientBuildManifestsManifestsMap<EntryKey, ClientBuildManifest>packages/next/src/shared/lib/turbopack/manifest-loader.ts:188-189
fontManifestsManifestsMap<EntryKey, NextFontManifest>packages/next/src/shared/lib/turbopack/manifest-loader.ts:190-191
middlewareManifestsManifestsMap<EntryKey, TurbopackMiddlewareManifest>packages/next/src/shared/lib/turbopack/manifest-loader.ts:192-195
pagesManifestsManifestsMap<string, PagesManifest>packages/next/src/shared/lib/turbopack/manifest-loader.ts:196-197
sriManifestsManifestsMap<EntryKey, SubresourceIntegrityManifest>packages/next/src/shared/lib/turbopack/manifest-loader.ts:198-199

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 FileTarget EnvironmentKey Bootstrap ActionSources
next-turbopack.tsProduction PagesCalls initialize({}), sets up __turbopack_load_page_chunks__, and invokes hydrate()packages/next/src/client/next-turbopack.ts:1-45
app-next-turbopack.tsApp Router (Prod/Dev)Executes appBootstrap with app-index hydration and optional dev overlaypackages/next/src/client/app-next-turbopack.ts:1-29
next-dev-turbopack.tsDevelopment PagesInitializes 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 / OptionValidation Rule / Normalization TargetSources
distDirThrows an error if set to 'public' or an empty string ""packages/next/src/server/config.ts:387-401
sassOptions.functionsThrows an error if customized when running under Turbopackpackages/next/src/server/config.ts:566-576
experimental.cssChunkingResolves mode ('graph' requires Turbopack; 'strict' and false require Webpack)packages/next/src/server/config.ts:603-624
turbopack.chunkLoadingGlobalAutomatically prefixes global chunk names with TURBOPACK_ if missingpackages/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 OptionValue / SourceSources
rootPath`config.turbopack?.root
projectPath`normalizePath(path.relative(rootPath, dir)
watch.enablefalsepackages/next/src/build/turbopack-analyze/index.ts:61-63
buildId'analyze-build'packages/next/src/build/turbopack-analyze/index.ts:82-82
isPersistentCachingEnabledpersistentCachingpackages/next/src/build/turbopack-analyze/index.ts:93-93
turbopackMemoryEvictionconfig.experimental.turbopackMemoryEvictionModepackages/next/src/build/turbopack-analyze/index.ts:97-97
gcconfig.experimental.turbopackGcOptionspackages/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

Was this page helpful?