Relevant source files
The following files were used as context for generating this wiki page:
- packages/next/src/build/webpack-config.ts
- packages/next/src/build/webpack/loaders/next-swc-loader.ts
- packages/next/src/build/webpack/loaders/next-app-loader/index.ts
- packages/next/src/build/webpack/loaders/next-route-loader/index.ts
- packages/next/src/build/webpack/loaders/next-barrel-loader.ts
- packages/next/src/build/webpack/loaders/next-flight-client-entry-loader.ts
- packages/next/src/build/webpack/loaders/next-metadata-route-loader.ts
- packages/next/src/build/webpack/loaders/next-flight-client-module-loader.ts
- packages/next/src/build/babel/loader/index.ts
- packages/next/src/build/webpack/loaders/next-edge-app-route-loader/index.ts
- packages/next/src/build/webpack/loaders/next-flight-loader/index.ts
- packages/next/src/build/webpack/config/blocks/css/index.ts
- packages/next/src/build/webpack/loaders/next-edge-ssr-loader/index.ts
- packages/next-mdx/index.js
- packages/next/src/build/webpack/loaders/next-edge-function-loader.ts
- packages/next/src/build/webpack/loaders/next-flight-action-entry-loader.ts
- packages/next-mdx/mdx-rs-loader.js
- packages/next/src/build/webpack/config/blocks/css/loaders/index.ts
- packages/next/src/build/webpack/loaders/next-middleware-loader.ts
- packages/next/next-devtools.webpack-config.js
- packages/next/src/build/babel/loader/get-config.ts
- packages/next/src/build/get-babel-loader-config.ts
- packages/next/src/build/swc/index.ts
- packages/next/src/build/swc/install-bindings.ts
- packages/next/src/telemetry/events/swc-load-failure.ts
Overview
Next.js employs a specialized suite of webpack loaders to synthesize routing structures, handle SWC Compiler transformations, manage React Server Component boundaries, and optimize production bundles across diverse runtime environmentsWebpack Configuration. These loaders intercept raw source files and virtual entrypoints, injecting runtime adapters, transpiling modern syntax, pruning unused barrel exports, and resolving complex file-system hierarchies into executable JavaScript modules. By bridging filesystem conventions with bundler compilation rules, the loader architecture coordinates client browser execution, Node.js server rendering, and edge runtime compilation targets.
Sources: packages/next/src/build/webpack-config.ts:605-774, packages/next/src/build/webpack/loaders/next-swc-loader.ts:62-80
App router component tree synthesis
Execution Flow and SWC Integration
The loader sequence initializes native or WebAssembly SWC Compiler capabilities before processing any file-system paths. The traversal proceeds through a strict call chain: nextAppLoader invokes installBindings, which defers to loadBindings, which triggers tryLoadWasmWithFallback and finally records telemetry via eventSwcLoadFailure.
-
nextAppLoaderinitiates execution by callinginstallBindings()to guarantee compiler bindings are accessible early. Sources: packages/next/src/build/webpack/loaders/next-app-loader/index.ts:867-872 -
installBindingsdelegates execution toloadBindings(useWasmBinary)from the compiler module, ensuring environment variables likeNODE_ENVare locked before module loading. Sources: packages/next/src/build/swc/install-bindings.ts:16-23 -
loadBindingsevaluates platform compatibility and attempts to load native bindings or routes execution throughtryLoadWasmWithFallback. Sources: packages/next/src/build/swc/index.ts:198-256 -
tryLoadWasmWithFallbackattempts to initialize WebAssembly bindings or download fallback packages on demand when native binaries are unavailable. Sources: packages/next/src/build/swc/index.ts:331-379 -
eventSwcLoadFailurerecords failure metrics and loading status payloads (enabled,fallback, orfailed) via the telemetry storage provider. Sources: packages/next/src/telemetry/events/swc-load-failure.ts:21-71
Warning
When executing via Turbopack in a subprocess, installBindings cannot pass the useWasmBinary flag because Turbopack runtime environments do not support WebAssembly compilation binaries.
Sources: packages/next/src/build/webpack/loaders/next-app-loader/index.ts:867-872
Segment Resolution and Path Normalization
next-app-loader extracts loader configurations, resolves application paths, and parses route segments to build the layout and page hierarchy. It uses absolute paths computed against the root app directory and parses base64-encoded proxy configurations for middleware routing.
const loaderOptions = this.getOptions()
const {
name,
appDir,
appPaths,
allNormalizedAppPaths: allNormalizedAppPathsOption,
pagePath,
pageExtensions,
rootDir,
tsconfigPath,
isDev,
nextConfigOutput,
preferredRegion,
basePath,
middlewareConfig: middlewareConfigBase64,
} = loaderOptions
const isGlobalNotFoundEnabled = !!loaderOptions.isGlobalNotFoundEnabled
const explicitParallelRouteChildren =
!!loaderOptions.explicitParallelRouteChildren
const strictRouteMatching = !!loaderOptions.strictRouteMatching
const isFinalRouteMatcher = !!loaderOptions.isFinalRouteMatcher
// Update FILE_TYPES on the very top-level of the loader
if (!isGlobalNotFoundEnabled) {
// @ts-expect-error this delete is only necessary while experimental
delete FILE_TYPES['global-not-found']
}
const buildInfo = getModuleBuildInfo((this as any)._module)
const collectedDeclarations: [string, string][] = []
// Use the page from loaderOptions directly instead of deriving it from name.
// The name (bundlePath) may have been normalized with normalizePagePath()
// which is designed for Pages Router and incorrectly duplicates /index paths
// (e.g., /index/page -> /index/index/page). The page parameter contains the
// correct unnormalized value.
const page = loaderOptions.page
const middlewareConfig: ProxyConfig = JSON.parse(
Buffer.from(middlewareConfigBase64, 'base64').toString()
)
buildInfo.route = {
page,
absolutePagePath: createAbsolutePath(appDir, pagePath),
preferredRegion,
middlewareConfig,
relatedModules: [],
}Sources: packages/next/src/build/webpack/loaders/next-app-loader/index.ts:873-921
The segment resolver resolveParallelSegments scans normalized app paths, identifying parallel route slots starting with @ characters and mapping pages to children segments.
const resolveParallelSegments = (
pathname: string
): [string, string | string[]][] => {
const matched: Record<string, string | string[]> = {}
let existingChildrenPath: string | undefined
for (const appPath of normalizedAppPaths) {
if (appPath.startsWith(pathname + '/')) {
const rest = appPath.slice(pathname.length + 1).split('/')
// It is the actual page, mark it specially.
if (rest.length === 1 && rest[0] === 'page') {
existingChildrenPath = appPath
matched.children = PAGE_SEGMENT
continue
}
const isParallelRoute = rest[0].startsWith('@')
if (isParallelRoute) {
if (rest.length === 2 && rest[1] === 'page') {
// We found a parallel route at this level. We don't want to mark it explicitly as the page segment,
// as that should be matched to the `children` slot. Instead, we use an array, to signal to `createSubtreePropsFromSegmentPath`
// that it needs to recursively fill in the loader tree code for the parallel route at the appropriate levels.
matched[rest[0]] = [PAGE_SEGMENT]
continue
}
// If it was a parallel route but we weren't able to find the page segment (ie, maybe the page is nested further)
// we first insert a special marker to ensure that we still process layout/default/etc at the slot level prior to continuing
// on to the page segment.
matched[rest[0]] = [PARALLEL_VIRTUAL_SEGMENT, ...rest.slice(1)]
continue
}
if (existingChildrenPath && matched.children !== rest[0]) {
// If we get here, it means we already set a `page` segment earlier in the loop,
// meaning we already matched a page to the `children` parallel segment.
const isIncomingParallelPage = appPath.includes('@')
const hasCurrentParallelPage = existingChildrenPath.includes('@')
if (isIncomingParallelPage) {
// The duplicate segment was for a parallel slot. In this case,
// rather than throwing an error, we can ignore it since this can happen for valid reasons.
// For example, when we attempt to normalize catch-all routes, we'll push potential slot matches so
// that they are available in the loader tree when we go to render the page.
// We only need to throw an error if the duplicate segment was for a regular page.
// For example, /app/(groupa)/page & /app/(groupb)/page is an error since it corresponds
// with the same path.
continue
} else if (!hasCurrentParallelPage && !isIncomingParallelPage) {
// Both the current `children` and the incoming `children` are regular pages.
throw new Error(
`You cannot have two parallel pages that resolve to the same path. Please check ${existingChildrenPath} and ${appPath}. Refer to the route group docs for more information: https://nextjs.org/docs/app/building-your-application/routing/route-groups`
)
}
}
existingChildrenPath = appPath
matched.children = rest[0]
}
}
return Object.entries(matched)
}Sources: packages/next/src/build/webpack/loaders/next-app-loader/index.ts:933-994
| Option Name | Target Property | Purpose |
|---|---|---|
name | string | Bundle identifier for the target route entrypoint |
appDir | string | Absolute filesystem path pointing to the app/ root directory |
appPaths | string | string[] | Normalized application path arrays mapped to the current segment |
pagePath | string | Relative filesystem path to the target page component file |
pageExtensions | string | string[] | Valid file extensions recognized for route resolution |
tsconfigPath | string | Path to the TypeScript configuration file for path aliases |
isDev | boolean | Compilation mode flag indicating active development environment |
Sources: packages/next/src/build/webpack/loaders/next-app-loader/index.ts:873-889
React Server Component boundary transforms
Identifying RSC Boundaries and Module Types
Next.js utilizes next-flight-loader alongside entry loaders to analyze source files during Webpack compilation, populating build info with RSC module metadata via getRSCModuleInformation. The loader classifies modules into specific types and handles source type resolution through getAssumedSourceType, mapping Webpack module types (javascript/auto, javascript/dynamic, javascript/esm) to assumed source types (auto, script, module, commonjs).
export function getAssumedSourceType(
mod: webpack.Module,
sourceType: SourceType
): SourceType {
const buildInfo = getModuleBuildInfo(mod)
const detectedClientEntryType = buildInfo?.rsc?.clientEntryType
const clientRefs = buildInfo?.rsc?.clientRefs || []
// It's tricky to detect the type of a client boundary, but we should always
// use the `module` type when we can, to support `export *` and `export from`
// syntax in other modules that import this client boundary.
if (sourceType === 'auto') {
if (detectedClientEntryType === 'auto') {
if (clientRefs.length === 0) {
// If there's zero export detected in the client boundary, and it's the
// `auto` type, we can safely assume it's a CJS module because it doesn't
// have ESM exports.
return 'commonjs'
} else if (!clientRefs.includes('*')) {
// Otherwise, we assume it's an ESM module.
return 'module'
}
} else if (detectedClientEntryType === 'cjs') {
return 'commonjs'
}
}
return sourceType
}Sources: packages/next/src/build/webpack/loaders/next-flight-loader/index.ts:25-54
| Module Type | Assumed Source Type | Handling Behavior |
|---|---|---|
javascript/auto | commonjs / module | Fallbacks to commonjs when clientRefs is empty and detectedClientEntryType is auto; otherwise assumes module. |
javascript/dynamic | script | Treated as a dynamic script module. |
javascript/esm | module | Forces ESM module parsing to support export syntax. |
Sources: packages/next/src/build/webpack/loaders/next-flight-loader/index.ts:25-54, packages/next/src/build/webpack/loaders/next-flight-loader/index.ts:225-236
Caution
Using export * inside a client boundary is strictly unsupported. When clientRefs contains *, next-flight-loader immediately aborts compilation by passing an Error to this.callback().
Sources: packages/next/src/build/webpack/loaders/next-flight-loader/index.ts:114-121
Client Entry and Server Action Transformation
When a module is identified as a client boundary (RSC_MODULE_TYPES.client), next-flight-loader generates either an ESM proxy wrapping references with registerClientReference from "react-server-dom-webpack/server" or a CommonJS proxy using createProxy from MODULE_PROXY_PATH.
let esmSource =
prefix +
`\
import { registerClientReference } from "react-server-dom-webpack/server";
`
for (const ref of clientRefs) {
if (ref === 'default') {
esmSource += `export default registerClientReference(
function() { throw new Error(${JSON.stringify(`Attempted to call the default \
export of ${stringifiedResourceKey} from the server, but it's on the client. \
It's not possible to invoke a client function from the server, it can only be \
rendered as a Component or passed to props of a Client Component.`)}); },
${stringifiedResourceKey},
"default",
);\n`
} else {
esmSource += `export const ${ref} = registerClientReference(
function() { throw new Error(${JSON.stringify(`Attempted to call ${ref}() from \
the server but ${ref} is on the client. It's not possible to invoke a client \
function from the server, it can only be rendered as a Component or passed to \
props of a Client Component.`)}); },
${stringifiedResourceKey},
${JSON.stringify(ref)},
);`
}
}Sources: packages/next/src/build/webpack/loaders/next-flight-loader/index.ts:123-148
For client entry bundles, next-flight-client-entry-loader processes incoming module definitions and server options to construct eager Webpack imports. It filters out CSS files during server-side rendering (SSR) compilation and applies explicit webpackExports optimization flags when specific identifiers are targeted.
export default function transformSource(
this: webpack.LoaderContext<NextFlightClientEntryLoaderOptions>
) {
let { modules, server } = this.getOptions()
const isServer = server === 'true'
if (!Array.isArray(modules)) {
modules = modules ? [modules] : []
}
const code = modules
.map((x) => JSON.parse(x) as FlightClientEntryModuleItem)
// Filter out CSS files in the SSR compilation
.filter(({ request }) => (isServer ? !regexCSS.test(request) : true))
.map(({ request, ids }: FlightClientEntryModuleItem) => {
const importPath = JSON.stringify(
request.startsWith(BARREL_OPTIMIZATION_PREFIX)
? request.replace(':', '!=!')
: request
)
// When we cannot determine the export names, we use eager mode to include the whole module.
// Otherwise, we use eager mode with webpackExports to only include the necessary exports.
// If we have '*' in the ids, we include all the imports
if (ids.length === 0 || ids.includes('*')) {
return `import(/* webpackMode: "eager" */ ${importPath});\n`
} else {
return `import(/* webpackMode: "eager", webpackExports: ${JSON.stringify(
ids
)} */ ${importPath});\n`
}
})
.join(';\n')Sources: packages/next/src/build/webpack/loaders/next-flight-client-entry-loader.ts:28-60
Sources: packages/next/src/build/webpack/loaders/next-flight-loader/index.ts:99-223
Additionally, next-flight-action-entry-loader parses action lists to produce dedicated re-exports for server actions, exposing reference IDs distinctly through next-flight-server-reference-proxy-loader?id=... proxies during production builds.
function nextFlightActionEntryLoader(
this: webpack.LoaderContext<NextFlightActionEntryLoaderOptions>
) {
const { actions }: NextFlightActionEntryLoaderOptions = this.getOptions()
const actionList = JSON.parse(actions) as FlightActionEntryLoaderActions
const individualActions = actionList
.map(([path, actionsFromModule]) => {
return actionsFromModule.map(({ id, exportedName }) => {
return [id, path, exportedName] as const
})
})
.flat()
return `
${individualActions
.map(([id, path, exportedName]) => {
// Re-export the same functions from the original module path as action IDs.
return `export { ${exportedName} as "${id}" } from ${JSON.stringify(path)}`
})
.join('\n')}
`
}Sources: packages/next/src/build/webpack/loaders/next-flight-action-entry-loader.ts:12-34
SWC compilation and worker execution
Transpilation and Binding Execution
Transpilation execution is handled through SWC Compiler bindings integrated via next-swc-loader. The loader checks whether source files require transpilation by applying exclusions and verifying conditions such as next/font, next/dynamic, use server, use client, or use cache. When a file requires processing, next-swc-loader calls getLoaderSWCOptions to construct compiler options and invokes transform.
async function loaderTransform(
this: LoaderContext<SWCLoaderOptions> & TelemetryLoaderContext,
source?: string,
inputSourceMap?: any
) {
// Make the loader async
const filename = this.resourcePath
// Ensure `.d.ts` are not processed.
if (filename.endsWith('.d.ts')) {
return [source, inputSourceMap]
}
let loaderOptions: SWCLoaderOptions = this.getOptions() || {}
const shouldMaybeExclude = maybeExclude(
filename,
loaderOptions.transpilePackages || []
)
const trackDynamicImports = shouldTrackDynamicImports(loaderOptions)
if (shouldMaybeExclude) {
if (!source) {
throw new Error(`Invariant might be excluded but missing source`)
}
const forceTranspileConditions = trackDynamicImports
? FORCE_TRANSPILE_CONDITIONS_WITH_IMPORT
: FORCE_TRANSPILE_CONDITIONS
if (!forceTranspileConditions.test(source)) {
return [source, inputSourceMap]
}
}Sources: packages/next/src/build/webpack/loaders/next-swc-loader.ts:91-124
Native or WebAssembly bindings are loaded and managed through a step-by-step resolution sequence. This pipeline begins when an entry wrapper invokes native installation:
nextAppLoader— Executes initial setup and calls binding installation. Sources: packages/next/src/build/webpack/loaders/next-app-loader/index.ts:867-872installBindings— Lazily requires[[SWC Compiler]]index module to deferNODE_ENVevaluation. Sources: packages/next/src/build/swc/install-bindings.ts:16-23loadBindings— Asynchronously checks platform triples, manages pending promises, and attempts native or WASM binary loading. Sources: packages/next/src/build/swc/index.ts:198-302loadNative— Searches local built directories ornode_modulesfor platform-specific.nodebinaries, checking version mismatches. Sources: packages/next/src/build/swc/index.ts:1571-1616bindingToApi— Wraps raw native functions into an API object implementing subscription iterators and project option serializers. Sources: packages/next/src/build/swc/index.ts:503-506ProjectImpl— Manages native project instances, worker scheduling, compilation subscriptions, and HMR updates. Sources: packages/next/src/build/swc/index.ts:687-700
Sources: packages/next/src/build/webpack/loaders/next-app-loader/index.ts:867-872, packages/next/src/build/swc/install-bindings.ts:16-23, packages/next/src/build/swc/index.ts:198-302, packages/next/src/build/swc/index.ts:1571-1616, packages/next/src/build/swc/index.ts:503-506, packages/next/src/build/swc/index.ts:687-700
Telemetry Hooks and Options Handling
When transformations complete, telemetry loader contexts are updated using output metrics from transform results. If binding loading fails, failure events collect runtime configuration, platform identifiers, and installed package data.
export async function eventSwcLoadFailure(
event?: Pick<
EventSwcLoadFailure['payload'],
'wasm' | 'nativeBindingsErrorCode'
>
): Promise<void> {
const telemetry: Telemetry | undefined = traceGlobals.get('telemetry')
// can't continue if telemetry isn't set
if (!telemetry) return
let glibcVersion
let installedSwcPackages
try {
// @ts-ignore
glibcVersion = process.report?.getReport().header.glibcVersionRuntime
} catch {}
try {
const pkgNames = Object.keys(optionalDependencies || {}).filter((pkg) =>
pkg.startsWith('@next/swc')
)
const installedPkgs = []
for (const pkg of pkgNames) {
try {
const { version } = require(`${pkg}/package.json`)
installedPkgs.push(`${pkg}@${version}`)
} catch {}
}
if (installedPkgs.length > 0) {
installedSwcPackages = installedPkgs.sort().join(',')
}
} catch {}
telemetry.record({
eventName: EVENT_PLUGIN_PRESENT,
payload: {
nextVersion: process.env.__NEXT_VERSION as string,
glibcVersion,
installedSwcPackages,
arch: process.arch,
platform: process.platform,
nodeVersion: process.versions.node,
wasm: event?.wasm,
nativeBindingsErrorCode: event?.nativeBindingsErrorCode,
},
})
// ensure this event is flushed before process exits
await telemetry.flush()
}Sources: packages/next/src/telemetry/events/swc-load-failure.ts:21-72
| Telemetry Payload Field | Type | Description |
|---|---|---|
platform | string | Operating system platform (process.platform). |
arch | string | CPU architecture (process.arch). |
nodeVersion | string | Node.js version string (process.versions.node). |
nextVersion | string | Next.js version from process.env.__NEXT_VERSION. |
wasm | 'enabled' | 'fallback' | 'failed' | Status of WebAssembly binary execution or fallback usage. |
glibcVersion | string | Runtime glibc version retrieved via process reporting. |
installedSwcPackages | string | Sorted comma-separated list of installed @next/swc package versions. |
nativeBindingsErrorCode | string | Error code thrown during native binding load attempts. |
Sources: packages/next/src/telemetry/events/swc-load-failure.ts:7-19
Warning
Failing to load SWC bindings does not call process.exit() directly inside synchronous fallback paths; errors are propagated to the caller's error handler so that telemetry buffers can flush properly before process termination.
Sources: packages/next/src/build/swc/index.ts:389-394, packages/next/src/telemetry/events/swc-load-failure.ts:70-72
Pages and edge entry wrappers
Route Generation and Loader Options
The route loaders generate entrypoints and adapters across server and Edge runtime targets. The next-route-loader builds loader entries for standard PAGES and PAGES_API routes using base64-encoded middleware configurations and absolute paths.
type RouteLoaderOptionsPagesAPIInput = {
kind: RouteKind.PAGES_API
page: string
preferredRegion: string | string[] | undefined
absolutePagePath: string
middlewareConfig: ProxyConfig
}
type RouteLoaderOptionsPagesInput = {
kind: RouteKind.PAGES
page: string
pages: MappedPages
preferredRegion: string | string[] | undefined
absolutePagePath: string
middlewareConfig: ProxyConfig
}
type RouteLoaderOptionsInput =
| RouteLoaderOptionsPagesInput
| RouteLoaderOptionsPagesAPIInput
Sources: packages/next/src/build/webpack/loaders/next-route-loader/index.ts:16-36
| Option Field | Target Route Kind | Description |
|---|---|---|
kind | PAGES | PAGES_API | Discriminator for route type processing. |
page | PAGES | PAGES_API | Logical page route string. |
absolutePagePath | PAGES | PAGES_API | Absolute path to the userland page file. |
pages | PAGES | Mapped internal components including /_app and /_document. |
preferredRegion | PAGES | PAGES_API | Preferred deployment region or regions. |
middlewareConfig | PAGES | PAGES_API | Proxy configuration options for middleware matching. |
Sources: packages/next/src/build/webpack/loaders/next-route-loader/index.ts:16-32
Note
When compiling an instrumentation hook file via loadPages, next-route-loader appends an explicit export hoisting the register method from the userland module.
Sources: packages/next/src/build/webpack/loaders/next-route-loader/index.ts:169-174
Edge Runtime and Middleware Adapters
Edge runtimes and SSR adapters use specialized loaders to set up module build info, cache handlers, and runtime wrappers. next-edge-ssr-loader swaps traditional CommonJS paths for ESM folder distributions for pages SSR'd at the edge, whereas next-edge-function-loader wraps API handlers with wrapApiHandler and the edge adapter.
function swapDistFolderWithEsmDistFolder(path: string) {
return path.replace('next/dist/pages', 'next/dist/esm/pages')
}Sources: packages/next/src/build/webpack/loaders/next-edge-ssr-loader/index.ts:43-45
| Loader Module | Source File | Key Runtime Setup |
|---|---|---|
EdgeAppRouteLoader | next-edge-app-route-loader/index.ts | Sets buildInfo.nextEdgeSSR with isServerComponent and registers custom cache handlers. |
edgeSSRLoader | next-edge-ssr-loader/index.ts | Loads edge-ssr-app or edge-ssr entrypoints with route module options. |
nextEdgeFunctionLoader | next-edge-function-loader.ts | Imports web globals and exports nHandler wrapping API routes with adapter. |
middlewareLoader | next-middleware-loader.ts | Decodes base64 matchers and builds middleware module metadata. |
Sources: packages/next/src/build/webpack/loaders/next-edge-app-route-loader/index.ts:88-116, packages/next/src/build/webpack/loaders/next-edge-ssr-loader/index.ts:141-227, packages/next/src/build/webpack/loaders/next-edge-function-loader.ts:39-70, packages/next/src/build/webpack/loaders/next-middleware-loader.ts:53-84
Warning
nextEdgeFunctionLoader throws an explicit runtime error if the userland module does not export a default function when evaluating edge API functions.
Sources: packages/next/src/build/webpack/loaders/next-edge-function-loader.ts:57-60
Babel fallback and React Compiler
Legacy Babel Loader Pipeline
Next.js provides a Babel loader entrypoint (nextBabelLoaderOuter) that processes source files through Babel when SWC compilation is bypassed or when custom configuration files are present. The loader evaluates file characteristics (CharacteristicsGermaneToCaching), inspecting properties such as isStandalone, isServer, isPageFile, isNextDist, hasModuleExports, hasReactCompiler, fileExt, and configFilePath to build a deterministic cache key.
interface CharacteristicsGermaneToCaching {
isStandalone: boolean
isServer: boolean | undefined
isPageFile: boolean | undefined
isNextDist: boolean
hasModuleExports: boolean
hasReactCompiler: boolean
fileExt: string
configFilePath: string | undefined
}Sources: packages/next/src/build/babel/loader/get-config.ts:57-66
| Cache Characteristic | Type | Purpose |
|---|---|---|
isStandalone | boolean | Identifies standalone transformation mode (e.g., standalone React Compiler pipeline). |
isServer | boolean | undefined | Distinguishes server-side builds from client-side bundles. |
isPageFile | boolean | undefined | Marks files residing within the application pages directory. |
isNextDist | boolean | Identifies internal Next.js distribution modules requiring CommonJS interop. |
hasModuleExports | boolean | Detects presence of module.exports string tokens in the source file. |
hasReactCompiler | boolean | Indicates whether React Compiler plugins are enabled and applicable. |
fileExt | string | Extracted file extension suffix (defaulting to 'unknown'). |
configFilePath | string | undefined | Path to an external Babel configuration file (.babelrc, .json, .js). |
Sources: packages/next/src/build/babel/loader/get-config.ts:57-66
Note
getCacheCharacteristics skips invoking isReactCompilerRequired unless hasReactCompiler is true and shouldSkipBabel evaluates to true, avoiding expensive SWC AST parsing operations on files that do not require transformation.
Sources: packages/next/src/build/babel/loader/get-config.ts:134-139
Custom Babel Configuration and Deprecation Warnings
When a custom configuration file path is provided via loaderOptions.configFile, getCustomBabelConfig reads JSON/JSON5 or JavaScript configuration formats. The loader explicitly rejects .mjs and .cjs configuration files by throwing an error.
function getCustomBabelConfig(configFilePath: string) {
if (isJsonFile.exec(configFilePath)) {
const babelConfigRaw = readFileSync(configFilePath, 'utf8')
return JSON5.parse(babelConfigRaw)
} else if (isJsFile.exec(configFilePath)) {
return require(configFilePath)
}
throw new Error(
'The Next.js Babel loader does not support .mjs or .cjs config files.'
)
}Sources: packages/next/src/build/babel/loader/get-config.ts:253-263
checkCustomBabelConfigDeprecation analyzes user configurations to detect plugins that can be natively migrated to SWC compiler options in next.config.js.
| Custom Babel Plugin | Corresponding Next.js Config Key (next.config.js) |
|---|---|
styled-components / babel-plugin-styled-components | compiler.styledComponents |
@emotion/babel-plugin | compiler.emotion |
relay / babel-plugin-relay | compiler.relay |
react-remove-properties / babel-plugin-react-remove-properties | compiler.reactRemoveProperties |
transform-remove-console / babel-plugin-transform-remove-console | compiler.removeConsole |
Sources: packages/next/src/build/babel/loader/get-config.ts:304-332
Warning
checkCustomBabelConfigDeprecation raises soft warning logs only when custom configurations contain unsupported or migratable plugins alongside the default next/babel preset, without halting the compilation process.
Sources: packages/next/src/build/babel/loader/get-config.ts:272-277, packages/next/src/build/babel/loader/get-config.ts:340-345
React Compiler Pipeline Integration
getReactCompilerLoader configures an isolated standalone Babel loader instance dedicated to executing babel-plugin-react-compiler. It resolves the compiler package, detects the installed React major version from cwd, and builds environment configurations such as enableNameAnonymousFunctions and target.
try {
const reactPkgPath = require.resolve('react/package.json', {
paths: [cwd],
})
const majorVersion: string = require(reactPkgPath).version.split('.')[0]
if (majorVersion === '18') {
target = majorVersion
}Sources: packages/next/src/build/get-babel-loader-config.ts:30-37
Caution
If babel-plugin-react-compiler cannot be resolved via require.resolve, getReactCompiler throws an explicit runtime error stating that the package is required when using the React Compiler.
Sources: packages/next/src/build/get-babel-loader-config.ts:6-14
Import pruning and MDX transforms
Barrel Optimizations and Import Pruning
To optimize bundle surface area, [[Webpack Loaders]] utilizes next-barrel-loader to prune unused re-exports from barrel files. When a user imports specific names from a barrel module, the loader queries an in-memory cache (barrelTransformMappingCache) or invokes the __barrel_transform__ SWC Compiler transform to generate an export map JSON representing module identifiers, import paths, and exported names.
const barrelTransformMappingCache = new Map<
string,
{
exportList: [string, string, string][]
wildcardExports: string[]
isClientEntry: boolean
} | null
>()Sources: packages/next/src/build/webpack/loaders/next-barrel-loader.ts:97-104
For wildcard exports (export * from './a'), the loader inserts __barrel_optimize__ query markers instructing Webpack to recursively process submodules until matching export targets are isolated. If a non-barrel file lacks structured export maps, the loader safely re-exports the resource path.
if (!mapping) {
// This file isn't a barrel and we can't apply any optimizations. Let's re-export everything.
// Since this loader accepts `names` and the request is keyed with `names`, we can't simply
// return the original source here. That will create these imports with different names as
// different modules instances.
this.callback(null, `export * from ${JSON.stringify(this.resourcePath)}`)
return
}Sources: packages/next/src/build/webpack/loaders/next-barrel-loader.ts:281-288
Note
NextBarrelLoader calls this.clearDependencies() after resolving the mapping to prevent expensive, redundant file system watcher registrations on cached barrel subpaths.
Sources: packages/next/src/build/webpack/loaders/next-barrel-loader.ts:275-280
Markdown and MDX Transformation Pipeline
Compiling Markdown and MDX files relies on mdx-rs-loader, which replaces legacy JS-based transformation pipelines with the Rust-powered mdx-rs compiler. The initialization sequence coordinates multiple binding layers and format-aware compilation options.
nextAppLoaderinitializes the pipeline. Sources: packages/next/src/build/webpack/loaders/next-app-loader/index.ts:867-872installBindingstriggers binding preparation. Sources: packages/next/src/build/swc/install-bindings.ts:16-23
Related
On This Page
OverviewApp router component tree synthesisExecution Flow and SWC IntegrationSegment Resolution and Path NormalizationReact Server Component boundary transformsIdentifying RSC Boundaries and Module TypesClient Entry and Server Action TransformationSWC compilation and worker executionTranspilation and Binding ExecutionTelemetry Hooks and Options HandlingPages and edge entry wrappersRoute Generation and Loader OptionsEdge Runtime and Middleware AdaptersBabel fallback and React CompilerLegacy Babel Loader PipelineCustom Babel Configuration and Deprecation WarningsReact Compiler Pipeline IntegrationImport pruning and MDX transformsBarrel Optimizations and Import PruningMarkdown and MDX Transformation PipelineRelated