Relevant source files
The following files were used as context for generating this wiki page:
- packages/next/src/server/lib/trace/tracer.ts
- packages/next/src/server/lib/trace/local-span-recorder.ts
- packages/next/src/build/index.ts
- packages/next/src/server/lib/trace/constants.ts
- packages/next/src/build/webpack/plugins/profiling-plugin.ts
- packages/next/src/build/collect-build-traces.ts
- packages/next/src/trace/trace.ts
- packages/next/src/server/route-modules/pages/pages-handler.ts
- packages/next/src/cli/internal/turbo-trace-server.ts
- packages/next/src/build/turbopack-build/index.ts
- packages/next/src/server/lib/trace/request-insights.ts
- packages/next/src/server/lib/router-utils/instrumentation-globals.external.ts
- packages/next/src/server/lib/router-utils/instrumentation-node-extensions.ts
- packages/next/src/build/webpack/plugins/rspack-profiling-plugin.ts
- packages/next/src/server/lib/trace/span-store.ts
- packages/next/src/server/dev/next-dev-server.ts
- packages/next/src/build/analyze/index.ts
- packages/next/src/trace/trace-uploader.ts
- packages/next/src/bin/next.ts
- packages/next/src/trace/index.ts
- packages/next/src/build/utils.ts
- packages/next/src/next-devtools/dev-overlay/components/request-insights/trace-viewer.ts
- packages/next/src/trace/report/to-telemetry.ts
- packages/next/src/build/webpack/utils.ts
- packages/next/src/build/webpack/plugins/next-trace-entrypoints-plugin.ts
- packages/next/src/build/swc/generated-native.d.ts
- packages/next/src/server/lib/trace/request-insights-identity.ts
- packages/next/src/lib/memory/trace.ts
Overview
Next.js incorporates robust tracing and performance profiling subsystems designed to capture, record, and export telemetry data across both compilation pipelines and runtime request handlers. By leveraging standard OpenTelemetry instrumentation alongside custom local span recording mechanisms, the tracing engine provides granular visibility into execution paths, network request waterfalls, and resource utilization. Sources: packages/next/src/server/lib/trace/tracer.ts:223-278, packages/next/src/server/lib/trace/local-span-recorder.ts:58-81
The system addresses the challenge of diagnosing performance bottlenecks in complex asynchronous environments by combining asynchronous local storage propagation, bundler compilation hooks for Webpack and Rspack, output file dependency tracing via Vercel's NFT, and periodic V8 memory heap tracking. Sources: packages/next/src/build/webpack/plugins/profiling-plugin.ts:28-47, packages/next/src/build/collect-build-traces.ts:94-126, packages/next/src/lib/memory/trace.ts:27-54
Tracer Architecture and Core Span Lifecycle
Public Tracer Interface and Active Scope Management
Next.js exports a unified tracing surface combining OpenTelemetry wrappers with custom span management primitives. The NextTracerImpl class implements active scope resolution and context propagation using @opentelemetry/api. Active scope tracking through getActiveScopeSpan() inspects local span recorders when running in development mode before falling back to trace.getSpan(context.active()).
Note
NextTracerImpl attempts to require the user's installed version of @opentelemetry/api first to maintain compatibility with external OpenTelemetry tracing setups, falling back to the version bundled with Next.js only if the require call fails.
Context propagation is managed via withPropagatedContext and runWithDetachedContext. When executing synchronous or asynchronous blocks where upstream trace headers must be honored, withPropagatedContext extracts remote context carriers via propagation.extract using a provided or default TextMapGetter. If force is enabled, any extracted remote span context overrides the active context while merging baggage values. Conversely, runWithDetachedContext executes functions under ROOT_CONTEXT, ensuring that in-process Node.js middleware spawns sibling spans rather than nested child spans, matching the detached sandbox behavior of edge middleware.
Sources: packages/next/src/server/lib/trace/tracer.ts:42-50, packages/next/src/server/lib/trace/tracer.ts:252-330
OpenTelemetry Span Lifecycle Hooks
Span creation and duration recording are managed by the Span class in packages/next/src/trace/trace.ts alongside predefined span type enumerations. When a span starts, it captures a high-resolution timestamp via process.hrtime.bigint() and a wall-clock fallback via Date.now() to correlate monotonic durations with absolute epoch times.
Sources: packages/next/src/trace/trace.ts:30-164
The Span lifecycle supports manual and automatic tracking. Durations are calculated as nanosecond differences scaled down to microfluidic integer microseconds to fit safely within float64 bounds (Number.MAX_SAFE_INTEGER). If the calculated duration exceeds RECORD_SPAN_THRESHOLD_MS * 1000, the resulting TraceEvent is dispatched to the global reporter.
| Span Enumeration | Description / Key Members | Sources |
|---|---|---|
BaseServerSpan | Request handling, pipeline execution, server-side rendering (handleRequest, render, renderToHTML) | packages/next/src/server/lib/trace/constants.ts |
NextNodeServerSpan | Node server internals, component tree creation, routing, static generation (createComponentTree, findPageComponents, runApi) | packages/next/src/server/lib/trace/constants.ts |
AppRenderSpan | App Router rendering phases (renderToString, renderToReadableStream, fetch, waitShellReady) | packages/next/src/server/lib/trace/constants.ts |
RenderSpan | Pages Router data fetching and rendering (getServerSideProps, getStaticProps, renderDocument) | packages/next/src/server/lib/trace/constants.ts |
LoadComponents | Component and route module loading (loadComponents, loadRouteModule) | packages/next/src/server/lib/trace/constants.ts |
MiddlewareSpan | Middleware execution tracing (execute) | packages/next/src/server/lib/trace/constants.ts |
Caution
Calling .stop() multiple times on the same Span instance is guarded by a status check against SpanStatus.Stopped, returning early without reporting duplicate trace events. However, callers must ensure asynchronous functions wrapped with traceAsyncFn() properly await completion so that finally blocks call stop() at the correct boundary.
Sources: packages/next/src/server/lib/trace/constants.ts:10-134, packages/next/src/trace/trace.ts:75-103, packages/next/src/trace/trace.ts:154-164
Local Span Recording and Storage
In-Memory Collection and Async Storage Propagation
Local span recording captures telemetry directly within the development server environment without exporting to external OpenTelemetry collectors. This subsystem relies on AsyncLocalStorage instances managed across two storage boundaries: localSpanAsyncStorage via packages/next/src/server/lib/trace/local-span-recorder.ts and request-insights-identity-storage via packages/next/src/server/lib/trace/request-insights-identity.ts.
Sources: packages/next/src/server/lib/trace/local-span-recorder.ts:83-128, packages/next/src/server/lib/trace/request-insights-identity.ts:15-30
The function createLocalSpan instantiates LocalRecordingSpan with hex-encoded trace IDs and span IDs generated incrementally via getLocalTraceId() (32 hex characters) and getLocalSpanId() (16 hex characters). When traceLocalSpan wraps asynchronous operations, it automatically extracts the active local span's context, propagates parent identifiers, and isolates the span from the global OpenTelemetry pipeline by setting isolateOpenTelemetry: true.
Note
Request insights identity storage covers the portion of BaseServer request handling executing before app rendering establishes work storage. Once workStore is available, it functions as the primary identity source for locally recorded spans.
Sources: packages/next/src/server/lib/trace/local-span-recorder.ts:48-128, packages/next/src/server/lib/trace/request-insights-identity.ts:12-17
DevTools Integration and Recorder Registration
Span persistence and developer tooling integration are controlled by environment checks and registration functions defined in packages/next/src/server/lib/trace/span-store.ts. Local span recording is active only when process.env.__NEXT_DEV_SERVER is enabled alongside active test recorders or request insights flags.
| Function / Constant | Scope / Return Type | Description | Sources |
|---|---|---|---|
isLocalSpanRecordingEnabled() | boolean | Checks if __NEXT_DEV_SERVER is present and either test recorders or request insights are enabled. | packages/next/src/server/lib/trace/span-store.ts |
isRequestInsightsEnabled() | boolean | Validates if process.env.__NEXT_REQUEST_INSIGHTS matches enabled values (1, true, or boolean true). | packages/next/src/server/lib/trace/span-store.ts |
recordSpan(record) | void | Attaches a timestamp to the span record and dispatches it to test recorders or request insight collectors. | packages/next/src/server/lib/trace/span-store.ts |
registerLocalSpanRecorder() | void | Attaches a LocalSpanRecorder dictionary to globalThis under the symbol @next/local-span-recorder. | packages/next/src/server/lib/trace/local-span-recorder.ts |
Caution
recordSpan drops incoming records immediately without processing if isLocalSpanRecordingEnabled() evaluates to false, ensuring zero overhead during production builds where development server flags are absent.
Sources: packages/next/src/server/lib/trace/span-store.ts:45-76
Instrumentation Initialization and Node Augmentations
Instrumentation Hook Loading and Registration
Server startup initialization requires locating and loading the user-defined instrumentation hook file (instrumentation.js or instrumentation.ts compiled into the distribution directory). The module loader function getInstrumentationModule(projectDir, distDir) caches the resolved instrumentation object to prevent duplicate disk reads, using performance.timeOrigin + performance.performance.now() via getInstrumentationTimestamp() to measure module load timings.
export async function getInstrumentationModule(
projectDir: string,
distDir: string
): Promise<InstrumentationModule | undefined> {
if (cachedInstrumentationModule) {
return cachedInstrumentationModule
}
const startTime = getInstrumentationTimestamp()
let error: unknown
try {
cachedInstrumentationModule = interopDefault(
await require(
path.join(
projectDir,
distDir,
'server',
`${INSTRUMENTATION_HOOK_FILENAME}.js`
)
)
)
return cachedInstrumentationModule
} catch (err: unknown) {
if (
isError(err) &&
err.code !== 'ENOENT' &&
err.code !== 'MODULE_NOT_FOUND' &&
err.code !== 'ERR_MODULE_NOT_FOUND'
) {
error = err
throw err
}
} finally {
instrumentationModuleLoadTiming ??= {
startTime,
endTime: getInstrumentationTimestamp(),
error,
}
}
}Sources: packages/next/src/server/lib/router-utils/instrumentation-globals.external.ts:62-101
When registerInstrumentation(projectDir, distDir) executes, it checks process.env.NEXT_PHASE === 'phase-production-build' to bypass registration during production compilation. If the instrumentation module exports a register() asynchronous function, it executes the lifecycle hook, triggers extendInstrumentationAfterRegistration(), and emits backdated spans for both module loading and registration phases.
async function registerInstrumentation(projectDir: string, distDir: string) {
// Ensure registerInstrumentation is not called in production build
if (process.env.NEXT_PHASE === 'phase-production-build') {
return
}
if (!instrumentationModulePromise) {
instrumentationModulePromise = getInstrumentationModule(projectDir, distDir)
}
let instrumentation: InstrumentationModule | undefined
try {
instrumentation = await instrumentationModulePromise
} catch (err) {
// A load error is only exportable when a provider was already installed.
traceInstrumentationModuleLoad()
throw err
}
if (instrumentation?.register) {
const startTime = getInstrumentationTimestamp()
let error: unknown
try {
await instrumentation.register()
extendInstrumentationAfterRegistration()
} catch (err: any) {
error = err
err.message = `An error occurred while loading instrumentation hook: ${err.message}`
throw err
} finally {
const endTime = getInstrumentationTimestamp()
// register() commonly installs the provider, so emit both lifecycle
// spans afterward with their original timestamps.
traceInstrumentationModuleLoad()
traceBackdatedInstrumentationSpan(
InstrumentationSpan.register,
'register instrumentation',
{ startTime, endTime, error }
)
}
} else {
traceInstrumentationModuleLoad()
}
}Sources: packages/next/src/server/lib/router-utils/instrumentation-globals.external.ts:105-146
Warning
getInstrumentationModule ignores missing hook files by catching ENOENT, MODULE_NOT_FOUND, and ERR_MODULE_NOT_FOUND error codes silently, but rethrows any syntax or runtime errors encountered inside a present instrumentation file.
Sources: packages/next/src/server/lib/router-utils/instrumentation-globals.external.ts:84-93
Tracer Provider and Node Extensions
After successful registration, Node.js environment extensions modify OpenTelemetry tracer behaviors to integrate with React Server Components work units and cache components. The afterRegistration() function verifies that process.env.NEXT_RUNTIME !== 'edge' before invoking extendTracerProviderForCacheComponents().
Sources: packages/next/src/server/lib/router-utils/instrumentation-node-extensions.ts:18-26
| Function / Component | Target Scope | Description | Sources |
|---|---|---|---|
afterRegistration() | Node.js Runtime | Validates runtime is not edge and triggers tracer provider extensions. | packages/next/src/server/lib/router-utils/instrumentation-node-extensions.ts |
isProxyTracerProvider() | TracerProvider | Type guard checking for the presence of getDelegateTracer. | packages/next/src/server/lib/router-utils/instrumentation-node-extensions.ts |
instrumentTracerForCacheComponents() | Tracer | Patches startSpan and startActiveSpan to exit workUnitAsyncStorage during span creation. | packages/next/src/server/lib/router-utils/instrumentation-node-extensions.ts |
ensureInstrumentationRegistered() | Promise<void> | Memoizes registerInstrumentation to prevent concurrent multi-registration attempts. | packages/next/src/server/lib/router-utils/instrumentation-globals.external.ts |
Tip
The tracer extension attempts to load user-supplied @opentelemetry/api packages first, falling back to Next.js's bundled dependency version if the external module resolution fails.
Sources: packages/next/src/server/lib/router-utils/instrumentation-node-extensions.ts:52-57
Bundler Profiling and Tap Tracing
Webpack and Rspack Compilation Hooks
The ProfilingPlugin and RspackProfilingPlugin capture build metrics by attaching performance measurement spans to compiler tap hooks. Both plugins register lifecycle listeners on compilation phases to trace module construction, chunk generation, asset emission, and loader execution.
apply(compiler: any) {
this.traceTopLevelHooks(compiler)
this.traceCompilationHooks(compiler)
this.compiler = compiler
}
traceHookPair(
spanName: string | (() => string),
startHook: any,
stopHook: any,
{
parentSpan,
attrs,
onStart,
onStop,
}: {
parentSpan?: (...params: any[]) => Span
attrs?: any
onStart?: (span: Span, ...params: any[]) => void
onStop?: (span: Span, ...params: any[]) => void
} = {}
) {
let span: Span | undefined
startHook.tap(
{ name: pluginName, stage: -Infinity },
(...params: any[]) => {
const name = typeof spanName === 'function' ? spanName() : spanName
const attributes = attrs ? attrs(...params) : attrs
span = parentSpan
? parentSpan(...params).traceChild(name, attributes)
: this.runWebpackSpan.traceChild(name, attributes)
if (onStart) onStart(span, ...params)
}
)
stopHook.tap({ name: pluginName, stage: Infinity }, (...params: any[]) => {
// `stopHook` may be triggered when `startHook` has not in cases
// where `stopHook` is used as the terminating event for more
// than one pair of hooks.
if (!span) {
return
}
if (onStop) onStop(span, ...params)
span.stop()
})
}Sources: packages/next/src/build/webpack/plugins/profiling-plugin.ts:43-89
| Plugin Name | Target Compiler | Key Lifecycle Hooks | Stored Maps / WeakMaps | Sources |
|---|---|---|---|---|
ProfilingPlugin | Webpack | compilation, afterCompile, invalid, done, emit, afterEmit, make, buildModule, succeedModule, failedModule | spans, moduleSpansByCompilation, makeSpanByCompilation, sealSpanByCompilation, webpackInvalidSpans | packages/next/src/build/webpack/plugins/profiling-plugin.ts |
RspackProfilingPlugin | Rspack | thisCompilation, loader, buildModule, succeedModule | moduleSpansByCompilation, compilationSpans | packages/next/src/build/webpack/plugins/rspack-profiling-plugin.ts |
Warning
ProfilingPlugin registers startHook at -Infinity stage priority and stopHook at Infinity stage priority to ensure compilation boundaries encapsulate all intermediate plugin actions accurately.
Sources: packages/next/src/build/webpack/plugins/profiling-plugin.ts:66-78
Loader Span Profiling and Asset Traces
During module loading, both profiling plugins intercept the normal module loader hook to bind the active module span onto the Webpack or Rspack loaderContext under currentTraceSpan. This allows individual loaders to record custom child measurements inside the active module's lifetime.
moduleHooks.loader.tap(
pluginName,
(loaderContext: any, module: any) => {
const moduleSpan = moduleSpansByCompilation
.get(compilation)
?.get(module)
loaderContext.currentTraceSpan = moduleSpan
}
)
compilation.hooks.succeedModule.tap(pluginName, (module: any) => {
moduleSpansByCompilation?.get(compilation)?.get(module)?.stop()
})Sources: packages/next/src/build/webpack/plugins/profiling-plugin.ts:214-226
moduleHooks.loader.tap(
pluginName,
(loaderContext: any, module: any) => {
const moduleSpan = moduleSpansByCompilation
.get(compilation)
?.get(module)
loaderContext.currentTraceSpan = moduleSpan
}
)Sources: packages/next/src/build/webpack/plugins/rspack-profiling-plugin.ts:35-43
const TRACE_LABELS_SEAL = [
'module assets',
'create chunk assets',
'asset render',
'asset emit',
'store asset',
]Sources: packages/next/src/build/webpack/plugins/profiling-plugin.ts:16-22
Trace Export and Telemetry Reporting
Telemetry Reporting and Event Access Lists
Next.js exports specific internal trace events to anonymous telemetry via reportToTelemetry, which inspects a TRACE_EVENT_ACCESSLIST mapping. When a recorded trace event name matches an entry in this access list and telemetry storage is active via traceGlobals, it records the event payload with its duration in microseconds.
| Trace Event Name | Telemetry Event Identifier | Sources |
| --- | --- | --- | --- |
| webpack-invalidated | WEBPACK_INVALIDATED | packages/next/src/trace/report/to-telemetry.ts |
Sources: packages/next/src/trace/report/to-telemetry.ts:1-27
Trace Uploader and Allowed Event Filters
The trace uploader processes session trace output files line-by-line, filtering events against predefined allowed sets depending on whether execution is in development or build mode. Root spans and feature flags prefixed with feature. are gathered to populate request metadata, including git branch, commit hash, environment detection flags, and system architecture parameters.
| Mode / Set Constant | Allowed Event Names / Prefixes | Sources |
|---|---|---|
COMMON_ALLOWED_EVENTS | memory-usage, turbopack-persistence, turbopack-compaction, turbopack-module-graph, turbopack-write-entrypoints, turbopack-emit | packages/next/src/trace/trace-uploader.ts |
DEV_ALLOWED_EVENTS | client-hmr-latency, render-path, hot-reloader, webpack-invalid-client, webpack-invalidated-server, navigation-to-hydration, start-dev-server, compile-path, memory-usage, server-restart-close-to-memory-threshold plus common events | packages/next/src/trace/trace-uploader.ts |
BUILD_ALLOWED_EVENTS | next-build, run-turbopack, webpack-compilation, run-webpack-compiler, create-entrypoints, worker-main-edge-server, worker-main-client, worker-main-server, server, make, seal, chunk-graph, optimize-modules, optimize-chunks, optimize, optimize-tree, optimize-chunk-modules, module-hash, client, static-check, node-file-trace-build, static-generation, next-export, run-typescript, run-eslint plus common events | packages/next/src/trace/trace-uploader.ts |
Warning
Setting NEXT_TRACE_UPLOAD_FULL bypasses event name filtering to upload the entire trace file, which may fail if the build generated an excessively large trace payload.
Sources: packages/next/src/trace/trace-uploader.ts:65-75
Turbopack Trace Server and MCP Integration
The CLI utility startTurboTraceServerCli loads native SWC bindings and starts a background trace server handle alongside a Model Context Protocol (MCP) server instance on designated ports (wsPort default 5747, mcpPort defaulting to wsPort + 1). The MCP server exposes a query_spans tool supporting parameter filtering, child enumeration, pagination, sorting options (value, name, allocations, persistent-allocations), and recursive subtree searches.
export async function startTurboTraceServerCli(
file: string,
port: number | undefined,
mcpPort: number | undefined
) {
process.title = `next internal trace (v${process.env.__NEXT_VERSION})`
const wsPort = port ?? DEFAULT_WS_PORT
const httpPort = mcpPort ?? wsPort + 1
let bindings
try {
bindings = await loadBindings()
} catch {
console.error(
'Error: Could not load native bindings. The trace server requires native (non-WASM) bindings.'
)
process.exit(1)
}
let handle
try {
// Start the WebSocket trace server on a background thread (non-blocking).
handle = bindings.turbo.startTurbopackTraceServerHandle(file, wsPort)
} catch (err) {
console.error(
`Error: Could not start trace server for "${file}": ${err instanceof Error ? err.message : err}`
)
process.exit(1)
}
console.log(
`Turbopack trace server started. View trace at https://trace.nextjs.org?port=${wsPort}`
)
// Create the MCP server.
const mcpServer = new McpServer({
name: 'Next.js Trace Server MCP',
version: '0.1.0',
})
mcpServer.registerTool(
'query_spans',
{
description: [
'Query spans from a turbopack trace file: timing, CPU, attributes, allocation counters, and TurboMalloc live-memory samples.',
'',
'Navigation: pass a result `id` as `parent` to drill in. `search` is recursive over the whole subtree and returns full path IDs, so you can find a span without knowing where it lives. `depth` > 1 returns that many levels nested inline; `pageSize` (default 20, max 500) widens a page.',
'',
'Every response is paged: `totalCount` is how many matched in all, `totalPages` how many pages that is. Getting exactly `pageSize` results does not mean there are no more — check `totalCount`. Search cost scales with subtree size, so prefer scoping `parent` (or lowering `maxDepth`) over repeated root searches on a large trace.',
'',
'Allocations: `allocations` / `deallocations` / `allocationCount` and `persistentAllocations`, each with a `self*` counterpart excluding children. Comparing a total to its `self` shows whether a span allocates directly or only through descendants.',
'',
'`persistentAllocations` ranks allocators; it is NOT retained memory. It is allocated-minus-freed per TurboMalloc counters, which never see turbo-tasks cell or cache drops, so a total far above real peak RSS is expected rather than a leak. For absolute memory use `memorySummary` (count/start/end/min/peak/maxPressure, precomputed from `memorySamples`).',
'',
"But live heap is process-wide: a span's samples are just the global series sliced to its time range, so concurrent spans report identical memory however much each allocated. Rank concurrent work by the allocation fields, never by memory.",
'',
"Frees are charged to whichever span was on the stack at free time, not the one that allocated. A child with large `selfAllocations` under a parent with large `selfDeallocations` means the parent drops the child's arena — bounded, not leaking. Large `selfPersistentAllocations` with no such counterpart above it is the shape worth suspecting.",
'',
'For aggregated groups every allocation field is a group total, while `cpuDuration`, `correctedDuration` and `memorySamples` describe the example span only. `firstSpanId` is first in execution order; use `heaviestSpanId` to reach the member holding the most bytes.',
'',
'Set `outputType: "json"` for full precision and the raw `memorySamples` entries `[tsOffsetTicks, bytes, pressure, active_worker_threads]` (active_worker_threads excludes parked and blocking-pool threads); markdown is a human summary.',
].join('\n'),
inputSchema: {
parent: z
.string()
.optional()
.describe(
'Span ID to enumerate children of. Omit for root-level spans. Use the `id` field from a previous result.'
),
aggregated: z
.boolean()
.optional()
.describe(
'When true (default), aggregate spans with the same name into a single entry. Set to false to see individual raw spans.'
),
sort: z
.enum(['value', 'name', 'allocations', 'persistent-allocations'])
.optional()
.describe(
'Sort mode: "value" for corrected duration descending, "name" for alphabetical, "allocations" for total allocated bytes descending, "persistent-allocations" for `persistentAllocations` descending. Omit for execution order.'Sources: packages/next/src/cli/internal/turbo-trace-server.ts:169-255
Build File Tracing and Memory Sampling
Output File Tracing and Dependency Collection
Next.js computes production file dependencies using Vercel’s @vercel/nft (nodeFileTrace) during the build pipeline. The trace coordination functions in collectBuildTraces process server entries, custom incremental cache handlers, and middleware boundaries, while filtering out non-essential compilation assets and standalone development server modules.
| Artifact / Config Key | Target Path / Processing Rule | Sources |
|---|---|---|
next-server.js.nft.json | distDir/next-server.js.nft.json | packages/next/src/build/collect-build-traces.ts |
next-minimal-server.js.nft.json | distDir/next-minimal-server.js.nft.json | packages/next/src/build/collect-build-traces.ts |
outputFileTracingExcludes | Globs matching next-server added to additionalIgnores | packages/next/src/build/collect-build-traces.ts |
| Shared Ignore Patterns | **/next/dist/compiled/next-server/**/*.dev.js, **/next/dist/compiled/jest-worker/**/*, **/next/dist/compiled/webpack/*, **/node_modules/webpack5/**/* | packages/next/src/build/collect-build-traces.ts |
Note
During standalone mode builds, extra IPC server files, startup wrappers, and requirement hooks are explicitly pushed into sharedEntriesSet to ensure complete runtime tracing outside the standard development environment.
Sources: packages/next/src/build/collect-build-traces.ts:94-232, packages/next/src/build/utils.ts:1600-1635
Periodic V8 Memory Heap Tracing and Snapshots
The memory tracing subsystem tracks process memory footprint across process lifetimes by scheduling recurring snapshots via startPeriodicMemoryUsageTracing and logging metrics (memory.rss, memory.heapUsed, memory.heapTotal, memory.heapMax) into active OpenTelemetry spans or standard trace outputs.
| Metric Key | Description | Sources |
|---|---|---|
memory.rss | Resident Set Size obtained from process.memoryUsage() | packages/next/src/lib/memory/trace.ts |
memory.heapUsed | Used heap size obtained from v8.getHeapStatistics() | packages/next/src/lib/memory/trace.ts |
memory.heapTotal | Total heap size allocated | packages/next/src/lib/memory/trace.ts |
memory.heapMax | Maximum heap size limit (heap_size_limit) | packages/next/src/lib/memory/trace.ts |
Warning
When EXPERIMENTAL_DEBUG_MEMORY_USAGE is enabled and heap utilization exceeds HEAP_SNAPSHOT_THRESHOLD_PERCENT (70%), Next.js automatically writes a V8 heap snapshot to distDir on the first occurrence, guarded by the alreadyGeneratedHeapSnapshot flag to prevent duplicate disk writes.
Sources: packages/next/src/lib/memory/trace.ts:1-125
Related
On This Page
OverviewTracer Architecture and Core Span LifecyclePublic Tracer Interface and Active Scope ManagementOpenTelemetry Span Lifecycle HooksLocal Span Recording and StorageIn-Memory Collection and Async Storage PropagationDevTools Integration and Recorder RegistrationInstrumentation Initialization and Node AugmentationsInstrumentation Hook Loading and RegistrationTracer Provider and Node ExtensionsBundler Profiling and Tap TracingWebpack and Rspack Compilation HooksLoader Span Profiling and Asset TracesTrace Export and Telemetry ReportingTelemetry Reporting and Event Access ListsTrace Uploader and Allowed Event FiltersTurbopack Trace Server and MCP IntegrationBuild File Tracing and Memory SamplingOutput File Tracing and Dependency CollectionPeriodic V8 Memory Heap Tracing and SnapshotsRelated