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

Webpack Configuration

Last updated Oct 12, 2026100% grounded
Relevant source files

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

Overview

Next.js coordinates its build pipeline and development server by dynamically constructing compiler options Build Pipeline, Hot Reloading. The Webpack configuration system assembles specialized compilation targets across the browser client, Node.js server, and Edge Runtime environments Webpack Configuration. By chaining functional configuration blocksWebpack Configuration, it integrates SWC Compiler transformations Webpack Loaders, asset handling, and module aliasing Webpack Configuration. Adjacent manifest plugins and runtime builders consume these configuration outputs to generate application bundles, route loaders, and runtime artifacts Manifest Plugins, Route Discovery.

Sources: packages/next/src/build/webpack/config/index.ts:10-50, packages/next/src/build/webpack-config.ts:985-1007

Compiler target architecture

Compiler Environment Matrix

Next.js implements a multi-target compilation model that separates builds across three distinct environments: the Node.js server, the Edge Runtime server, and the browser client. During production compilation (webpackBuild), these targets are orchestrated sequentially or via worker threads in an ordered pipeline: server, edge-server, and client. Running the server compilers before the client compiler allows Next.js to track server/client component boundaries and dynamically inject client-side entry points discovered during server compilation.

Sources: packages/next/src/build/webpack-build/index.ts:14-18, packages/next/src/build/webpack-build/impl.ts:246-298

Compiler NameTarget EnvironmentKey Configuration & External Handling
serverNode.js ServerPresets node externals, applies handleExternals resolver, strips Node built-ins and Bun identifiers.
edge-serverEdge RuntimeConfigures edge polyfilled modules, party town fallbacks, and handleWebpackExternalForEdgeRuntime.
clientBrowser ClientBundles React and user code for browser execution, registers React Refresh and telemetry plugins.

Sources: packages/next/src/build/webpack-config.ts:987-1063, packages/next/src/build/webpack-build/impl.ts:175-203

Note

Server compilations execute prior to the client bundle so that client component entry points discovered via pluginState.injectedClientEntries can be accurately fed into the client compiler configuration. Sources: packages/next/src/build/webpack-build/impl.ts:232-288

Base configuration composition

Functional Pipeline Assembly

The construction of a Webpack configuration in Next.js is orchestrated by buildConfiguration, an asynchronous function that instantiates a ConfigurationContext object and pipes the initial webpack.Configuration through an array of functional blocks Webpack Configuration. The context encapsulates configuration flags such as hasAppDir, isDevelopment, isServer, isEdgeRuntime, targetWeb, rootDirectory, transpilePackages, and experimental features Webpack Configuration.

Sources: packages/next/src/build/webpack/config/index.ts:10-82

The pipeline uses a utility function pipe that reduces an array of configuration modifier functions sequentially, supporting both synchronous and asynchronous operations Webpack Configuration. By default, buildConfiguration incorporates the base block and the css block, and conditionally appends the images block unless disableStaticImages is explicitly enabled Webpack Configuration.

Function / UtilityFile PathPurpose
buildConfigurationpackages/next/src/build/webpack/config/index.tsMain entry point coordinating context setup and functional block piping.
pipepackages/next/src/build/webpack/config/utils.tsAsynchronous function reducer executing configuration transforms in sequence.
basepackages/next/src/build/webpack/config/blocks/base.tsCurried block configuring mode, target, devtool, and source map plugins.

Sources: packages/next/src/build/webpack/config/index.ts:10-82, packages/next/src/build/webpack/config/utils.ts:40-46, packages/next/src/build/webpack/config/blocks/base.ts:19-22

Note

The assetPrefix value normalized inside ConfigurationContext automatically strips any trailing slash from the provided input string to maintain consistent asset URL resolution across compilation targets. Sources: packages/next/src/build/webpack/config/index.ts:62-66

Base Configuration Block & Source Map Strategy

The base configuration block, curried using lodash.curry, assigns fundamental Webpack properties based on the ConfigurationContext Webpack Configuration. It sets config.mode to 'development' or 'production' and determines config.name using constants from COMPILER_NAMES (server, edgeServer, or client) Webpack Configuration. For non-web targets, it specifies node18.17, aligning with the engine version defined in packages/next/package.json Webpack Configuration.

Source map generation within the base block adapts dynamically depending on development mode, runtime environment, and experimental flags Webpack Configuration.

Conditionconfig.devtool SettingAssociated Plugin / Behavior
ctx.isDevelopment'eval-source-map' (Webpack) / Forked plugin (Rspack)Full-fidelity source maps with original variable names and columns for browser debugging.
ctx.isEdgeRuntime (Production)'source-map'Standard source map generation for edge runtime bundles.
ctx.isServer && ctx.serverSourceMaps (Production)'source-map'Enabled when server source maps are explicitly requested in configuration.
ctx.productionBrowserSourceMaps && ctx.isClient (Production)'source-map'Generates browser source maps for client production builds.
Default Production (Fallback)falseDisables source map generation to reduce bundle size and compile overhead.

Sources: packages/next/src/build/webpack/config/blocks/base.ts:36-54

Warning

When eval-source-map is active under Rspack or Webpack, the block resets config.devtool to false and explicitly injects either EvalSourceMapDevToolPlugin or getRspackCore().EvalSourceMapDevToolPlugin alongside DevToolsIgnorePlugin using path-ignoring rules. Sources: packages/next/src/build/webpack/config/blocks/base.ts:67-86

Module aliasing and resolution

Custom Module Aliases and Path Resolution

Next.js sets up comprehensive compiler aliases via createWebpackAliases to map project roots, page directories, app directories, and internal framework assets. During development, custom application and error pages (_app, _error, _document) are resolved via array aliases that fall back to internal Next.js default templates if the user files are absent.

if (dev) {
  const nextDistPath = 'next/dist/' + (isEdgeServer ? 'esm/' : '')
  customAppAliases[`${PAGES_DIR_ALIAS}/_app`] = [
    ...(pagesDir
      ? pageExtensions.reduce((prev, ext) => {
          prev.push(path.join(pagesDir, `_app.${ext}`))
          return prev
        }, [] as string[])
      : []),
    `${nextDistPath}pages/_app.js`,
  ]
  customAppAliases[`${PAGES_DIR_ALIAS}/_error`] = [
    ...(pagesDir
      ? pageExtensions.reduce((prev, ext) => {
          prev.push(path.join(pagesDir, `_error.${ext}`))
          return prev
        }, [] as string[])
      : []),
    `${nextDistPath}pages/_error.js`,
  ]
  customDocumentAliases[`${PAGES_DIR_ALIAS}/_document`] = [
    ...(pagesDir
      ? pageExtensions.reduce((prev, ext) => {
          prev.push(path.join(pagesDir, `_document.${ext}`))
          return prev
        }, [] as string[])
      : []),
    `${nextDistPath}pages/_document.js`,
  ]
}

Sources: packages/next/src/build/create-compiler-aliases.ts:73-102

Client compilers map the instrumentation stub (private-next-instrumentation-client) to INSTRUMENTATION_CLIENT_STUB_PATH, and resolve user instrumentation through private-next-instrumentation-client-user with a fallback to private-next-empty-module (which is configured as false to create a Webpack no-op module).

Alias Constant / KeyTarget Path / Resolution Behavior
@vercel/og$next/dist/server/og/image-response
next/dist/server/ReactDOMServerPagesreact-dom/server.edge (React 19) or react-dom/server.browser (React 18)
styled-jsx/style$defaultOverrides['styled-jsx/style']
PAGES_DIR_ALIASUser-defined pages directory (if present)
APP_DIR_ALIASUser-defined app directory (if present)
ROOT_DIR_ALIASAbsolute path to project root (dir)
DOT_NEXT_ALIASBuild output directory (distDir)
setimmediatenext/dist/compiled/setimmediate

Sources: packages/next/src/build/create-compiler-aliases.ts:105-252

Note

In browser bundles, createWebpackAliases iterates over browserVariantModules (generated from the filesystem) and maps every .js file under NEXT_PROJECT_ROOT_DIST to its .browser sibling to prevent server-only logic from leaking into client bundles. Sources: packages/next/src/build/create-compiler-aliases.ts:176-187

Vendored React Runtimes and Layer Mapping

Next.js vendors its own React channels and maps react, react-dom, and react-server-dom-webpack depending on the target environment condition (browser, edge, or nodejs) and React condition (client or server). The function createVendoredReactAliases builds these mappings based on the active bundledReactChannel ('' or '-experimental') and layer constraints.

export function createVendoredReactAliases(
  bundledReactChannel: BundledReactChannel,
  {
    layer,
    isBrowser,
    isEdgeServer,
    reactProductionProfiling,
  }: {
    layer: WebpackLayerName
    isBrowser: boolean
    isEdgeServer: boolean
    reactProductionProfiling: boolean
  }
): CompilerAliases {
  const environmentCondition = isBrowser
    ? 'browser'
    : isEdgeServer
      ? 'edge'
      : 'nodejs'
  const reactCondition = shouldUseReactServerCondition(layer)
    ? 'server'
    : 'client'
 
  // ✅ Correct alias

Sources: packages/next/src/build/create-compiler-aliases.ts:377-400

Server-only and client-only import guards are enforced via createServerOnlyClientOnlyAliases, which substitutes restricted packages with empty modules or compilation errors depending on whether the compiler runs on the server or client.

Module RequestServer Target ResolutionClient Target Resolution
server-only$next/dist/compiled/server-only/emptynext/dist/compiled/server-only/index
client-only$next/dist/compiled/client-only/errornext/dist/compiled/client-only/index
next/dist/compiled/server-only$next/dist/compiled/server-only/emptynext/dist/compiled/server-only/index
next/dist/compiled/client-only$next/dist/compiled/client-only/errornext/dist/compiled/client-only/index

Sources: packages/next/src/build/create-compiler-aliases.ts:254-274

Warning

If serverExternalPackages and transpilePackages contain overlapping package names, Webpack configuration initialization throws an error to prevent conflicting externalization and transpilation rules. Sources: packages/next/src/build/webpack-config.ts:883-894

Style processing and font loaders

CSS Loader Pipelines and PostCSS Integration

The CSS configuration block processes style sheets via modular loader pipelines, supporting global CSS, CSS modules, Sass variants (.scss, .sass), and font optimization. The core function css handles rule generation using curried configuration pipelines. Sass files are preprocessed by sass-loader, which compiles proprietary syntax and passes through CSS imports with sourceMap: true, followed by resolve-url-loader to rewrite relative paths. PostCSS transformations are initialized lazily via lazyPostCSS, attaching legacy plugin compatibility and vendor helpers (postcss.vendor.prefix and postcss.vendor.unprefixed).

export async function lazyPostCSS(
  rootDirectory: string,
  supportedBrowsers: string[] | undefined,
  disablePostcssPresetEnv: boolean | undefined,
  useLightningcss: boolean | undefined
) {
  if (!postcssInstancePromise) {
    postcssInstancePromise = (async () => {
      const postcss = require('postcss') as typeof import('postcss').default
      // @ts-ignore backwards compat
      postcss.plugin = function postcssPlugin(name, initializer) {
        function creator(...args: any) {
          let transformer = initializer(...args)
          transformer.postcssPlugin = name
          // transformer.postcssVersion = new Processor().version
          return transformer
        }
 
        let cache: any
        Object.defineProperty(creator, 'postcss', {
          get() {
            if (!cache) cache = creator()
            return cache
          },
        })
 
        creator.process = function (
          css: any,
          processOpts: any,
          pluginOpts: any
        ) {
          return postcss([creator(pluginOpts)]).process(css, processOpts)
        }
 
        return creator
      }
 
      // @ts-ignore backwards compat
      postcss.vendor = {
        /**
         * Returns the vendor prefix extracted from an input string.
         *
         * @example
         * postcss.vendor.prefix('-moz-tab-size') //=> '-moz-'
         * postcss.vendor.prefix('tab-size')      //=> ''
         */
        prefix: function prefix(prop: string): string {
          const match = prop.match(/^(-\w+-)/)
 
          if (match) {
            return match[0]
          }
 
          return ''
        },
 
        /**
         * Returns the input string stripped of its vendor prefix.
         *
         * @example
         * postcss.vendor.unprefixed('-moz-tab-size') //=> 'tab-size'
         */
        unprefixed: function unprefixed(
          /**
           * String with or without vendor prefix.
           */
          prop: string
        ): string {
          return prop.replace(/^-\w+-/, '')
        },
      }

Sources: packages/next/src/build/webpack/config/blocks/css/index.ts:58-128

Client-side style loading delegates to getClientStyleLoader, which inspects environment flags to determine whether to inject development style tags or production chunk extracts.

Environment / Target ConditionLoader UsedLoader Options / Insertion Behavior
Development (pages/ directory)next-style-loaderInserts style elements directly before the DOM anchor element #__next_css__DO_NOT_USE__ inside <head>
Production or App Directory (isDevelopment: false or shouldEnableApp: true)MiniCssExtractPlugin.loaderSets publicPath to ${assetPrefix}/_next/ (or / if experimentalInlineCss is active) and esModule: false

Sources: packages/next/src/build/webpack/config/blocks/css/loaders/client.ts:4-60

Note

MiniCssExtractPlugin disables ordering warnings (ignoreOrder: true) because Next.js guarantees safe CSS code-splitting through strict module scoping and single entrypoint global CSS constraints. Sources: packages/next/src/build/webpack/config/blocks/css/index.ts:589-617

Rspack Core Checks and Font Extraction

When executing builds with Rspack (NEXT_RSPACK), style extraction utilizes Rspack's internal CSS plugin architecture. The resolution helper getRspackCore checks availability and logs experimental notices using a deduplicated LRU warning cache.

export function getRspackCore() {
  warnRspack()
  try {
    // eslint-disable-next-line @next/internal/typechecked-require
    return require('next-rspack/rspack-core')
  } catch (e) {
    if (e instanceof Error && 'code' in e && e.code === 'MODULE_NOT_FOUND') {
      throw new Error(
        '@rspack/core is not available. Please make sure `next-rspack` is correctly installed.'
      )
    }
 
    throw e
  }
}

Sources: packages/next/src/shared/lib/get-rspack.ts:3-17

Font extraction rules match target files against Google and local font loader definitions, running getNextFontLoader to configure css-loader in pure mode alongside next-font-loader.

export function getNextFontLoader(
  ctx: ConfigurationContext,
  postcss: any,
  fontLoaderPath: string
): webpack.RuleSetUseItem[] {
  const loaders: webpack.RuleSetUseItem[] = []
 
  if (ctx.isClient) {
    // Add appropriate development mode or production mode style
    // loader
    loaders.push(
      getClientStyleLoader({
        hasAppDir: ctx.hasAppDir,
        isDevelopment: ctx.isDevelopment,
        assetPrefix: ctx.assetPrefix,
      })
    )
  }
 
  loaders.push({
    loader: require.resolve('../../../../loaders/css-loader/src'),
    options: {
      postcss,
      importLoaders: 1,
      // Use CJS mode for backwards compatibility:
      esModule: false,
      url: (url: string, resourcePath: string) =>
        cssFileResolve(url, resourcePath, ctx.experimental.urlImports),
      import: (url: string, _: any, resourcePath: string) =>
        cssFileResolve(url, resourcePath, ctx.experimental.urlImports),
      modules: {
        // Do not transform class names (CJS mode backwards compatibility):
        exportLocalsConvention: 'asIs',
        // Server-side (Node.js) rendering support:
        exportOnlyLocals: ctx.isServer,
        // Disallow global style exports so we can code-split CSS and
        // not worry about loading order.
        mode: 'pure',
        getLocalIdent: (
          _context: any,
          _localIdentName: any,
          exportName: string,
          _options: any,
          meta: any
        ) => {
          // hash from next-font-loader
          return `__${exportName}_${meta.fontFamilyHash}`
        },
      },
      fontLoader: true,
    },
  })
 
  loaders.push({
    loader: 'next-font-loader',
    options: {
      isDev: ctx.isDevelopment,
      isServer: ctx.isServer,
      assetPrefix: ctx.assetPrefix,
      deploymentId: ctx.deploymentId,
      fontLoaderPath,
      postcss,
    },
  })
 
  return loaders

Sources: packages/next/src/build/webpack/config/blocks/css/loaders/next-font.ts:6-71

The following call chain demonstrates how Rspack core checks emit deduplicated warnings during style and font loader initialization:

  1. css calls getNextFontLoader
  2. getNextFontLoader invokes getClientStyleLoader
  3. getClientStyleLoader evaluates getRspackCore
  4. getRspackCore executes warnRspack
  5. warnRspack invokes warnOnce
  6. warnOnce queries has on the internal LRU cache
  7. If absent, set adds the warning key to LRUNode structures
  8. warn delegates to prefixedLog to render console outputs
export const css: (
  ctx: ConfigurationContext
) => (config: webpack.Configuration) => Promise<webpack.Configuration> = curry(
  async function css(ctx: ConfigurationContext, config: webpack.Configuration) {

Sources: packages/next/src/build/webpack/config/blocks/css/index.ts:147-150, packages/next/src/build/webpack/config/blocks/css/loaders/next-font.ts:6-10, packages/next/src/build/webpack/config/blocks/css/loaders/client.ts:4-19, packages/next/src/shared/lib/get-rspack.ts:3-25, packages/next/src/build/output/log.ts:77-84

Caution

calculateSize functions passed to LRUCache must always return a positive integer greater than zero; returning zero causes unbounded cache growth because zero-size items are never evicted. Sources: packages/next/src/server/lib/lru-cache.ts:130-135

Edge Runtime module constraints

Edge externals and polyfilled modules

For edge server compilation targets, Webpack configuration externally manages built-in packages and polyfills via custom external handlers and fallback definitions. Packages such as @builder.io/partytown and next/dist/compiled/etag resolve to empty objects ({}) to satisfy runtime requirements within lightweight V8 isolates.

...(isEdgeServer
  ? [
      {
        '@builder.io/partytown': '{}',
        'next/dist/compiled/etag': '{}',
      },
      getEdgePolyfilledModules(),
      handleWebpackExternalForEdgeRuntime,
    ]

Sources: packages/next/src/build/webpack-config.ts:997-1005

Note

Edge server configurations exclude standard Node.js built-in modules from direct bundling, routing them instead through handleWebpackExternalForEdgeRuntime and specialized polyfills. Sources: packages/next/src/build/webpack-config.ts:987-1007

Middleware plugin and unsupported Node APIs

The MiddlewarePlugin inspects module graphs and assets for Edge functions and middleware execution contexts. It enforces module constraints by checking usage against known edge-safe packages and tracking unsupported Node.js API usage.

const KNOWN_SAFE_DYNAMIC_PACKAGES =
  require('../../../lib/known-edge-safe-packages.json') as string[]
 

Sources: packages/next/src/build/webpack/plugins/middleware-plugin.ts:41-43

Warning

Importing restricted Node.js core modules into edge runtime files triggers build errors via static analysis and unsupported API detection routines. Sources: packages/next/src/build/webpack/plugins/middleware-plugin.ts:14-16

Internal tooling configurations

Build-time runtime and devtools bundling

Next.js maintains dedicated configuration files (next-runtime.webpack-config.js and next-devtools.webpack-config.js) processed via task runner pipelines to compile internal runtimes, workers, and developer tools using Rspack core bindings and @rspack/core.

const webpack = require('@rspack/core')
const path = require('path')
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer')
const DevToolsIgnoreListPlugin = require('./webpack-plugins/devtools-ignore-list-plugin')

Sources: packages/next/next-runtime.webpack-config.js:1-4

const path = require('path')
const webpack = require('@rspack/core')
const MODERN_BROWSERSLIST_TARGET = require('./src/shared/lib/modern-browserslist-target')
const DevToolsIgnoreListPlugin = require('./webpack-plugins/devtools-ignore-list-plugin')

Sources: packages/next/next-devtools.webpack-config.js:1-4

Bundle TypeEntry Point PathOutput DirectoryTarget / Mode
app-pagedist/esm/server/route-modules/app-page/module.jsdist/compiled/next-servernode / dev or prod
app-routedist/esm/server/route-modules/app-route/module.jsdist/compiled/next-servernode / dev or prod
pagesdist/esm/server/route-modules/pages/module.jsdist/compiled/next-servernode / dev or prod
pages-apidist/esm/server/route-modules/pages-api/module.jsdist/compiled/next-servernode / dev or prod
serverdist/esm/server/next-server.jsdist/compiled/next-servernode / dev or prod
use-cache-probe-workerdist/esm/server/dev/use-cache-probe-worker.jsdist/compiled/next-servernode / dev or prod
dev-validation-workerdist/esm/server/dev/dev-validation-worker.jsdist/compiled/next-servernode / dev or prod
next-devtoolssrc/next-devtools/entrypoint.tsdist/compiled/next-devtoolsbrowserslist / dev or prod

Sources: packages/next/next-runtime.webpack-config.js:91-124, packages/next/next-runtime.webpack-config.js:205-214, packages/next/next-devtools.webpack-config.js:27-32

Note

The app-worker bundle category groups development validation and cache probe workers, dynamically resolving native SWC binding graphs from the installed runtime tree instead of bundling them under dist/esm. Sources: packages/next/next-runtime.webpack-config.js:114-123, packages/next/next-runtime.webpack-config.js:160-172

Webpack hook aliasing and local resolution

Build scripts load custom hook aliases via loadWebpackHook to intercept webpack, webpack/package, webpack-sources, and associated compiler components, redirecting requests to Next.js compiled versions unless custom user Webpack environments are requested via environment variables.

export function loadWebpackHook(webpackProjectDir: string) {
  if (installed) {
    return
  }
  installed = true
 
  const requireHook =
    require('../server/require-hook') as typeof import('../server/require-hook')
  const customWebpack = Boolean(process.env.NEXT_PRIVATE_LOCAL_WEBPACK)
  if (customWebpack) {

Sources: packages/next/src/server/config-utils.ts:3-12

const webpackAliases: [string, string][] = [
  ['webpack', 'next/dist/compiled/webpack/webpack-lib'],
  ['webpack/package', 'next/dist/compiled/webpack/package'],
  ['webpack/package.json', 'next/dist/compiled/webpack/package'],
  ['webpack/lib/webpack', 'next/dist/compiled/webpack/webpack-lib'],
  ['webpack/lib/webpack.js', 'next/dist/compiled/webpack/webpack-lib'],
  [
    'webpack/lib/node/NodeEnvironmentPlugin',
    'next/dist/compiled/webpack/NodeEnvironmentPlugin',
  ],
  [
    'webpack/lib/node/NodeEnvironmentPlugin.js',
    'next/dist/compiled/webpack/NodeEnvironmentPlugin',
  ],
  [
    'webpack/lib/BasicEvaluatedExpression',
    'next/dist/compiled/webpack/BasicEvaluatedExpression',
  ],

Sources: packages/next/src/server/config-utils.ts:24-41

Warning

Setting NEXT_PRIVATE_LOCAL_WEBPACK forces project-level module resolution for Webpack dependencies, triggering unrecoverable build errors if the target project lacks an installed webpack package in its dependencies. Sources: packages/next/src/server/config-utils.ts:11-22

Was this page helpful?