---
title: "Telemetry"
description: "Next.js telemetry provides an anonymous data collection system designed to capture usage patterns, feature adoption, compilation results, and performance diagnostics, helping shape product roadmaps..."
last_updated: "2026-10-12T06:38:56.875594+00:00"
canonical_url: "https://www.doc0.dev/docs/8f4009b0-65bd-4480-9b00-e201f0914bb3/technical/cli-telemetry/telemetry"
---

<details>
<summary>Relevant source files</summary>

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

- [packages/next/src/telemetry/storage.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/telemetry/storage.ts)
- [packages/next/src/build/index.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/index.ts)
- [packages/next/src/server/dev/hot-reloader-turbopack.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/dev/hot-reloader-turbopack.ts)
- [packages/next/src/telemetry/flush-telemetry.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/telemetry/flush-telemetry.ts)
- [packages/next/src/next-devtools/userspace/app/forward-logs.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/next-devtools/userspace/app/forward-logs.ts)
- [packages/next/src/trace/report/to-telemetry.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/trace/report/to-telemetry.ts)
- [packages/next/src/server/dev/hot-reloader-webpack.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/dev/hot-reloader-webpack.ts)
- [packages/next/src/server/mcp/mcp-telemetry-tracker.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/mcp/mcp-telemetry-tracker.ts)
- [packages/next/src/telemetry/detached-flush.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/telemetry/detached-flush.ts)
- [packages/next/src/telemetry/post-telemetry-payload.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/telemetry/post-telemetry-payload.ts)
- [packages/next/src/server/lib/trace/request-insights.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/lib/trace/request-insights.ts)
- [packages/next/src/telemetry/events/swc-load-failure.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/telemetry/events/swc-load-failure.ts)
- [packages/next/src/cli/next-telemetry.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/cli/next-telemetry.ts)
- [packages/next/src/next-devtools/dev-overlay.browser.tsx](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/next-devtools/dev-overlay.browser.tsx)
- [packages/next/src/build/webpack/plugins/telemetry-plugin/telemetry-plugin.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/webpack/plugins/telemetry-plugin/telemetry-plugin.ts)
- [packages/devlow-bench/src/interfaces/snowflake.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/devlow-bench/src/interfaces/snowflake.ts)
- [packages/next/src/next-devtools/dev-overlay/utils/save-devtools-config.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/next-devtools/dev-overlay/utils/save-devtools-config.ts)
- [packages/next/src/trace/trace-uploader.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/trace/trace-uploader.ts)
- [packages/next/src/telemetry/events/index.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/telemetry/events/index.ts)
- [packages/next/src/trace/report/index.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/trace/report/index.ts)
- [packages/next/src/server/client-component-renderer-logger.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/client-component-renderer-logger.ts)
- [packages/next/src/client/dev/hot-reloader/runtime-error-state.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/dev/hot-reloader/runtime-error-state.ts)
- [packages/next/src/telemetry/events/agent-upgrade.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/telemetry/events/agent-upgrade.ts)
- [packages/next/src/telemetry/events/build.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/telemetry/events/build.ts)
- [packages/next/src/server/dev/browser-logs/file-logger.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/dev/browser-logs/file-logger.ts)
- [packages/next/src/server/lib/trace/span-store.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/lib/trace/span-store.ts)
- [packages/next/src/trace/report/to-json.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/trace/report/to-json.ts)
- [packages/next/src/next-devtools/userspace/app/terminal-logging-config.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/next-devtools/userspace/app/terminal-logging-config.ts)
- [packages/next/src/telemetry/events/session-stopped.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/telemetry/events/session-stopped.ts)
- [packages/next/src/telemetry/anonymous-meta.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/telemetry/anonymous-meta.ts)
</details>

## Overview

Next.js telemetry provides an anonymous data collection system designed to capture usage patterns, feature adoption, compilation results, and performance diagnostics, helping shape product roadmaps and prioritize features. Operating via persistent local configuration stores and secure identity hashing, the telemetry subsystem records events locally, buffers payloads in memory, and dispatches them securely over HTTPS to upstream collection endpoints while preserving end-user privacy.
Sources: [packages/next/src/telemetry/storage.ts:14-30](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/telemetry/storage.ts#L14-L30), [packages/next/src/telemetry/storage.ts:346-360](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/telemetry/storage.ts#L346-L360), [packages/next/src/telemetry/post-telemetry-payload.ts:25-29](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/telemetry/post-telemetry-payload.ts#L25-L29)

The infrastructure integrates deeply across the [build pipeline](https://www.doc0.dev/docs/8f4009b0-65bd-4480-9b00-e201f0914bb3/technical/build-system/build-pipeline), compiler plugins, CLI execution lifecycle, and OpenTelemetry tracing bridges to gather granular insights. It incorporates robust opt-out mechanisms, background flushing workers for process lifecycles, and environment variable controls to ensure telemetry collection remains transparent and fully controllable.
Sources: [packages/next/src/build/index.ts:4902-4911](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/index.ts#L4902-L4911), [packages/next/src/telemetry/detached-flush.ts:51-53](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/telemetry/detached-flush.ts#L51-L53), [packages/next/src/cli/next-telemetry.ts:14-22](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/cli/next-telemetry.ts#L14-L22)

## Telemetry storage architecture and identity hashing

### Core Telemetry Class and Configuration Storage

The `Telemetry` class coordinates local event recording, persistent configuration management, and payload dispatch. During instantiation, it reads environment variables (`NEXT_TELEMETRY_DISABLED` and `NEXT_TELEMETRY_DEBUG`) to determine operating modes and initializes a storage directory using `getStorageDirectory`. Ephemeral environments such as continuous integration servers or Docker containers resolve storage to `path.join(distDir, 'cache')`, while standard developer workstations omit a dedicated local directory override. The class wraps Next.js's compiled `Conf` library under the project name `nextjs`, catching permission initialization errors to prevent process crashes. A cryptographically secure session identifier (`sessionId`) is generated using 32 random bytes converted to a hex string, while an in-memory queue (`Set<Promise<RecordObject>>`) tracks active submission promises.
Sources: [packages/next/src/telemetry/storage.ts:40-89](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/telemetry/storage.ts#L40-L89)

| Constant Name | Value / Key | Purpose |
| --- | --- | --- |
| `TELEMETRY_KEY_ENABLED` | `telemetry.enabled` | Stores whether telemetry collection is enabled or disabled. |
| `TELEMETRY_KEY_NOTIFY_DATE` | `telemetry.notifiedAt` | Specifies when the user was first informed about anonymous telemetry. |
| `TELEMETRY_KEY_ID` | `telemetry.anonymousId` | Quasi-persistent identifier used to deduplicate recurring events anonymously. |
| `TELEMETRY_KEY_SALT` | `telemetry.salt` | Cryptographic salt included within hashed values to prevent dictionary lookups. |

Sources: [packages/next/src/telemetry/storage.ts:14-30](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/telemetry/storage.ts#L14-L30)

> [!NOTE]
> The `Conf` persistence layer handles initialization permission errors via a try-catch block, falling back to a null configuration reference to prevent unexpected application crashes during startup.
> Sources: [packages/next/src/telemetry/storage.ts:75-82](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/telemetry/storage.ts#L75-L82)

### Anonymous Identity and Hashing Mechanics

Persistent user identification relies on the `anonymousId` getter, which checks the local configuration store for `telemetry.anonymousId`. If absent, it generates a new 32-byte random hex string and caches it in the configuration store. Project identification utilizes `getRawProjectId`, pairing local configuration contexts with raw project identifiers to scope events. To maintain user privacy, all sensitive payloads pass through irreversible hashing mechanisms incorporating a per-installation cryptographic salt (`telemetry.salt`). This salt value is never transmitted upstream, neutralizing pre-computed dictionary attacks and ensuring that submitted telemetry data remains strictly non-identifiable.
Sources: [packages/next/src/telemetry/storage.ts:11-29](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/telemetry/storage.ts#L11-L29), [packages/next/src/telemetry/storage.ts:120-131](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/telemetry/storage.ts#L120-L131)

## Anonymous system metadata collection

### Host Platform and Machine Indicators

The `getAnonymousMeta` function gathers execution context and environment metadata by inspecting host operating system interfaces and environment variables. Host metrics include the platform type, release version, system architecture, CPU core count, primary CPU model, and CPU speed via the Node.js `os` module. Memory capacity is calculated by converting total system memory from bytes to megabytes and rounding to the nearest integer.
Sources: [packages/next/src/telemetry/anonymous-meta.ts:3-43](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/telemetry/anonymous-meta.ts#L3-L43)

| Trait Property | Source / Expression | Description |
| --- | --- | --- |
| `systemPlatform` | `os.platform()` | Operating system platform identifier. |
| `systemRelease` | `os.release()` | Operating system release version. |
| `systemArchitecture` | `os.arch()` | System CPU architecture. |
| `cpuCount` | `cpus.length` | Total number of available CPU cores. |
| `cpuModel` | `cpus.length ? cpus[0].model : null` | Model designation of the primary CPU. |
| `cpuSpeed` | `cpus.length ? cpus[0].speed : null` | Clock speed of the primary CPU in megahertz. |
| `memoryInMb` | `Math.trunc(os.totalmem() / Math.pow(1024, 2))` | Total system memory truncated to megabytes. |

Sources: [packages/next/src/telemetry/anonymous-meta.ts:35-43](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/telemetry/anonymous-meta.ts#L35-L43)

> [!NOTE]
> Metadata payloads are cached in the module-scoped `traits` variable upon initial resolution, ensuring that subsequent telemetry submissions reuse identical payload metadata without re-querying system interfaces.
> Sources: [packages/next/src/telemetry/anonymous-meta.ts:25-30](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/telemetry/anonymous-meta.ts#L25-L30)

### Environment and Container Detection

Containerization, continuous integration services, and developer tooling indicators are collected alongside core machine statistics. Container presence is evaluated using `is-docker`, Windows Subsystem for Linux detection relies on `is-wsl`, and local development environments verify whether `NOW_REGION` is set to `'dev1'`. Continuous integration status and vendor identity are resolved via `../server/ci-info`, while package manager or execution agent names are populated asynchronously using `getAgentName()`. The active framework release is captured directly from `process.env.__NEXT_VERSION`.
Sources: [packages/next/src/telemetry/anonymous-meta.ts:1-22](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/telemetry/anonymous-meta.ts#L1-L22), [packages/next/src/telemetry/anonymous-meta.ts:44-52](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/telemetry/anonymous-meta.ts#L44-L52)

## Event queuing and synchronous flush

### In-Memory Buffering and Queue State

The `Telemetry` class maintains an in-memory event queue represented as a `Set` of promises tracking asynchronous record operations (`this.queue = new Set()`). When telemetry is recorded, single events or arrays of events are normalized into a `TelemetryEvent` array. If debugging is enabled via `NEXT_TELEMETRY_DEBUG`, events bypass network dispatch and instead log the serialized payload alongside resolved anonymous metadata to standard error after a short timeout.
Sources: [packages/next/src/telemetry/storage.ts:31-38](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/telemetry/storage.ts#L31-L38), [packages/next/src/telemetry/storage.ts:59-60](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/telemetry/storage.ts#L59-L60), [packages/next/src/telemetry/storage.ts:306-338](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/telemetry/storage.ts#L306-L338)

> [!WARNING]
> Telemetry recording returns an immediate resolved promise if the feature is globally disabled via `this.isDisabled` or if an empty event array is provided, preventing unnecessary allocations or execution overhead.
> Sources: [packages/next/src/telemetry/storage.ts:316-318](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/telemetry/storage.ts#L316-L318), [packages/next/src/telemetry/storage.ts:341-343](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/telemetry/storage.ts#L341-L343)

### HTTPS Payload Dispatch and Retry Policies

Payload submission is handled by `postNextTelemetryPayload`, which dispatches HTTPS requests to the telemetry collection endpoint via the Fetch API using `next/dist/compiled/async-retry`. If an incoming `AbortSignal` is absent and `AbortSignal.timeout` is supported, a default 5000-millisecond timeout signal is instantiated. The request configuration options and retry policies are structured explicitly to constrain network latency during dispatch operations.
Sources: [packages/next/src/telemetry/post-telemetry-payload.ts:1-38](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/telemetry/post-telemetry-payload.ts#L1-L38), [packages/next/src/telemetry/storage.ts:345-365](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/telemetry/storage.ts#L345-L365)

| Parameter | Value | Description |
| --- | --- | --- |
| Endpoint URL | `https://telemetry.nextjs.org/api/v1/record` | Destination HTTPS endpoint for telemetry payloads. |
| HTTP Method | `POST` | HTTP method used for dispatching event data. |
| Content-Type | `application/json` | Request header specifying JSON payload formatting. |
| `minTimeout` | `500` | Initial retry delay in milliseconds. |
| `retries` | `1` | Maximum number of retry attempts upon failure. |
| `factor` | `1` | Exponential backoff factor applied between retries. |

Sources: [packages/next/src/telemetry/post-telemetry-payload.ts:23-38](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/telemetry/post-telemetry-payload.ts#L23-L38)

> [!NOTE]
> Network errors and non-OK HTTP responses are caught and swallowed silently to guarantee that telemetry failures never disrupt or crash the main application process.
> Sources: [packages/next/src/telemetry/post-telemetry-payload.ts:30-47](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/telemetry/post-telemetry-payload.ts#L30-L47)

Global telemetry flushing is coordinated across modules through `flushTelemetry`, which retrieves the active telemetry instance from `traceGlobals` and awaits its `flush` routine.
Sources: [packages/next/src/telemetry/flush-telemetry.ts:1-9](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/telemetry/flush-telemetry.ts#L1-L9)

## Detached background telemetry flushing

### Argument Parsing and Execution Validation

The detached background telemetry flushing mechanism is implemented as an immediately invoked asynchronous function in `packages/next/src/telemetry/detached-flush.ts`. It expects process arguments to follow a precise ordering: mode, project directory, an optional events filename, and an optional resolved distribution directory.
Sources: [packages/next/src/telemetry/detached-flush.ts:9-15](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/telemetry/detached-flush.ts#L9-L15)

```typescript
if (!dir || mode !== 'dev') {
  throw new Error(
    `Invalid flags should be run as node detached-flush dev ./path-to/project [eventsFile] [distDir]`
  )
}
```
Sources: [packages/next/src/telemetry/detached-flush.ts:18-22](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/telemetry/detached-flush.ts#L18-L22)

```typescript
dir = getProjectDir(dir)
```
Sources: [packages/next/src/telemetry/detached-flush.ts:23-23](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/telemetry/detached-flush.ts#L23-L23)

> [!WARNING]
> If `inputDir` is omitted or `mode` is not `'dev'`, the script throws an error enforcing the exact node invocation syntax.
> Sources: [packages/next/src/telemetry/detached-flush.ts:18-22](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/telemetry/detached-flush.ts#L18-L22)

### Distribution Directory and Event Batch Resolution

To avoid reloading phase-specific configuration when build nudges pass their resolved output directories, the script conditionally resolves `distDir`. Named batches live in the `.next/cache` directory to prevent build cleanup from removing them prior to submission, while callers without an events filename fall back to the legacy root `_events.json` location.
Sources: [packages/next/src/telemetry/detached-flush.ts:25-38](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/telemetry/detached-flush.ts#L25-L38)

```typescript
// Build nudges pass their resolved output directory to avoid loading dev config again.
const distDir = suppliedDistDir
  ? path.resolve(suppliedDistDir)
  : path.join(
      dir,
      (await loadConfig(PHASE_DEVELOPMENT_SERVER, dir)).distDir || '.next'
    )

// Named batches live in cache so build cleanup cannot remove them before submission.
// Retain the legacy root path for callers without an events filename.
const eventsPath =
  eventsFile && !eventsFile.includes('/')
    ? path.join(distDir, 'cache', eventsFile)
    : path.join(distDir, '_events.json')
```
Sources: [packages/next/src/telemetry/detached-flush.ts:25-38](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/telemetry/detached-flush.ts#L25-L38)

> [!NOTE]
> If the events file does not exist (`ENOENT`), the worker catches the error code and exits immediately with code `0` since there are no events to process.
> Sources: [packages/next/src/telemetry/detached-flush.ts:41-49](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/telemetry/detached-flush.ts#L41-L49)

### Event Recording, Flushing, and Cleanup

Once the event payload is read and parsed as JSON, a new `Telemetry` instance is initialized using the resolved `distDir`. The worker records the events, initiates a flush, unlinks the events file upon completion, and allows Node.js to exit naturally.
Sources: [packages/next/src/telemetry/detached-flush.ts:51-59](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/telemetry/detached-flush.ts#L51-L59)

```typescript
  const telemetry = new Telemetry({ distDir })
  await telemetry.record(events)
  await telemetry.flush()

  // finished flushing events clean-up
  fs.unlinkSync(eventsPath)
  // Don't call process.exit() here - let Node.js exit naturally after
  // all pending work completes (e.g., setTimeout in debug telemetry)
})()
```
Sources: [packages/next/src/telemetry/detached-flush.ts:51-59](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/telemetry/detached-flush.ts#L51-L59)

## Compilation and feature adoption events

### Build Outcomes and Optimization Telemetry

Next.js records comprehensive telemetry during compilation phases via functions defined in `packages/next/src/telemetry/events/build.ts`. The `eventBuildCompleted` and `eventBuildOptimize` factories evaluate page paths against regex rules to categorize project layout traits, specifically identifying test files or directories via `/[\\/]__(tests|mocks)__[\\/]/i` or `/\.(?:spec|test)\.[^.]+$/i`, and dunder directories via `/[\\/]__[^\\/]+(?<![\\/]__(?:tests|mocks))__[\\/]/i`.
Sources: [packages/next/src/telemetry/events/build.ts:5-108](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/telemetry/events/build.ts#L5-L108), [packages/next/src/telemetry/events/build.ts:151-178](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/telemetry/events/build.ts#L151-L178)

```typescript
const EVENT_BUILD_COMPLETED = 'NEXT_BUILD_COMPLETED'
type EventBuildCompleted = {
  bundler: 'webpack' | 'rspack' | 'turbopack'
  durationInSeconds: number
  totalPageCount: number
  hasDunderPages: boolean
  hasTestPages: boolean
  totalAppPagesCount?: number
}
```
Sources: [packages/next/src/telemetry/events/build.ts:76-84](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/telemetry/events/build.ts#L76-L84)

> [!NOTE]
> `NEXT_BUILD_OPTIMIZED` aggregates detailed route metrics including static, server, SSR, and [edge runtime](https://www.doc0.dev/docs/8f4009b0-65bd-4480-9b00-e201f0914bb3/technical/server-runtime/edge-runtime) counts for both pages and [App Router](https://www.doc0.dev/docs/8f4009b0-65bd-4480-9b00-e201f0914bb3/technical/client-runtime/app-router) directories, alongside route matcher counts like `headersCount`, `rewritesCount`, and `redirectsCount`.
> Sources: [packages/next/src/telemetry/events/build.ts:124-149](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/telemetry/events/build.ts#L124-L149)

### SWC Feature Detection and Compiler Failures

The `TelemetryPlugin` inspects the Webpack `ModuleGraph` during compilation by tapping into module finish hooks to resolve incoming connections and count unique origin imports for specific features. When `next-swc` native binding loads fail, `eventSwcLoadFailure` gathers host runtime diagnostics including `glibcVersion` from `process.report?.getReport().header.glibcVersionRuntime` and installed optional SWC package versions.
Sources: [packages/next/src/build/webpack/plugins/telemetry-plugin/telemetry-plugin.ts:168-235](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/webpack/plugins/telemetry-plugin/telemetry-plugin.ts#L168-L235), [packages/next/src/telemetry/events/swc-load-failure.ts:21-55](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/telemetry/events/swc-load-failure.ts#L21-L55)

```typescript
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:57-71](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/telemetry/events/swc-load-failure.ts#L57-L71)

| Feature Name | Module Path or Regexp Identifier | Category |
| :--- | :--- | :--- |
| `next/image` | `/next/image.js` | Built-in Component |
| `next/future/image` | `/next/future/image.js` | Built-in Component |
| `next/legacy/image` | `/next/legacy/image.js` | Built-in Component |
| `next/script` | `/next/script.js` | Built-in Component |
| `next/dynamic` | `/next/dynamic.js` | Built-in Component |
| `@next/font/google` | `/\/@next\/font\/google\/target\.css\?.+$/` | [Font Optimization](https://www.doc0.dev/docs/8f4009b0-65bd-4480-9b00-e201f0914bb3/technical/built-in-features/font-optimization) |
| `@next/font/local` | `/\/@next\/font\/local\/target\.css\?.+$/` | Font Optimization |
| `next/font/google` | `/\/next\/font\/google\/target\.css\?.+$/` | Font Optimization |
| `next/font/local` | `/\/next\/font\/local\/target\.css\?.+$/` | Font Optimization |

Sources: [packages/next/src/build/webpack/plugins/telemetry-plugin/telemetry-plugin.ts:65-77](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/webpack/plugins/telemetry-plugin/telemetry-plugin.ts#L65-L77)

> [!WARNING]
> `eventErrorThrown` intentionally strips out error message contents to protect user privacy, recording solely the error class name (`errorCode`) and any anonymized internal source tree location path.
> Sources: [packages/next/src/telemetry/events/build.ts:311-326](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/telemetry/events/build.ts#L311-L326)

## CLI lifecycle and upgrade telemetry

### Session Stop Events and MCP Tool Tracking

Next.js monitors CLI usage by capturing session termination via `eventCliSessionStopped`, which records environment identifiers and directory structures under `NEXT_CLI_SESSION_STOPPED`. Version checking relies strictly on `process.env.__NEXT_VERSION`; if unpopulated, payload emission is aborted. Alongside core CLI metrics, `McpTelemetryTracker` records tool invocation counts for Model Context Protocol features.
Sources: [packages/next/src/server/mcp/mcp-telemetry-tracker.ts:1-47](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/mcp/mcp-telemetry-tracker.ts#L1-L47), [packages/next/src/telemetry/events/session-stopped.ts:1-39](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/telemetry/events/session-stopped.ts#L1-L39)

```typescript
const payload: EventCliSessionStopped = {
  nextVersion: process.env.__NEXT_VERSION,
  nodeVersion: process.version,
  cliCommand: event.cliCommand,
  durationMilliseconds: event.durationMilliseconds,
  ...(typeof event.turboFlag !== 'undefined'
    ? {
        turboFlag: !!event.turboFlag,
      }
    : {}),
  pagesDir: event.pagesDir,
  appDir: event.appDir,
  isRspack: process.env.NEXT_RSPACK !== undefined,
}
```
Sources: [packages/next/src/telemetry/events/session-stopped.ts:25-38](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/telemetry/events/session-stopped.ts#L25-L38)

| Payload Field | Type | Description |
| :--- | :--- | :--- |
| `cliCommand` | `string` | The invoked CLI command name |
| `nextVersion` | `string` | Resolved from `process.env.__NEXT_VERSION` |
| `nodeVersion` | `string` | Resolved from `process.version` |
| `turboFlag` | `boolean \| null` | Indicates if Turbopack was requested |
| `durationMilliseconds` | `number \| null` | Total session execution duration |
| `pagesDir` | `boolean` | Presence of a pages directory |
| `appDir` | `boolean` | Presence of an app directory |
| `isRspack` | `boolean` | Resolved from `process.env.NEXT_RSPACK !== undefined` |

Sources: [packages/next/src/telemetry/events/session-stopped.ts:3-12](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/telemetry/events/session-stopped.ts#L3-L12), [packages/next/src/telemetry/events/session-stopped.ts:25-38](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/telemetry/events/session-stopped.ts#L25-L38)

> [!WARNING]
> `eventCliSessionStopped` acts as an invariant check for build tooling: if `process.env.__NEXT_VERSION` is not a string, the event array is dropped entirely rather than emitting incomplete version metadata.
> Sources: [packages/next/src/telemetry/events/session-stopped.ts:20-23](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/telemetry/events/session-stopped.ts#L20-L23)

### Agent Upgrade and Nudge Telemetry

The telemetry infrastructure tracks automated upgrade policies, nudge prompts, and agent execution results using structured event factories. Every generated event wraps its payload with `schemaVersion: 1`. Policy detection, user prompt interactions, run initiations, and CLI results are emitted via distinct event channels to separate configuration reach from operational outcomes.
Sources: [packages/next/src/telemetry/events/agent-upgrade.ts:28-97](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/telemetry/events/agent-upgrade.ts#L28-L97)

| Type Identifier | Allowed Values / Structure | Purpose |
| :--- | :--- | :--- |
| `AgentUpgradePolicy` | `'security'`, `'latest'`, `'experimental-future'` | Defines upgrade strictness |
| `AgentUpgradeOrigin` | `'human_manual'`, `'human_nudge'`, `'agent_manual'`, `'agent_nudge'` | Tracks how an upgrade run started |
| `AgentUpgradeHandoffMethod` | `'existing_agent'`, `'launched_agent'`, `'copied_prompt'`, `'printed_prompt'` | Describes prompt delivery mechanism |
| `AgentUpgradeCLIResult` | `'no_update_needed'`, `'no_safe_target'`, `'metadata_failure'`, `'guide_failure'`, `'cancelled'`, `'handoff_issued'`, `'handoff_failed'`, `'cli_failure'` | Reports CLI preparation and delivery result |

Sources: [packages/next/src/telemetry/events/agent-upgrade.ts:4-27](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/telemetry/events/agent-upgrade.ts#L4-L27)

> [!TIP]
> `eventAgentUpgradeCLIResult` captures the CLI's preparation and prompt delivery stages, whereas `eventAgentUpgradeAgentResult` separately records the agent's verified execution outcome (`success` or `failure`) and its resulting version.
> Sources: [packages/next/src/telemetry/events/agent-upgrade.ts:78-97](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/telemetry/events/agent-upgrade.ts#L78-L97)

## Trace span telemetry reporting

Next.js bridges internal [Trace Profiling](https://www.doc0.dev/docs/8f4009b0-65bd-4480-9b00-e201f0914bb3/technical/cli-telemetry/trace-profiling) spans into the telemetry dispatcher via `reportToTelemetry` within [Trace Profiling](https://www.doc0.dev/docs/8f4009b0-65bd-4480-9b00-e201f0914bb3/technical/cli-telemetry/trace-profiling). The bridge maps incoming trace event names against a fixed access list, filtering out unlisted metrics before querying global telemetry state. When an active telemetry instance is retrieved from `traceGlobals`, matching trace events are recorded with their execution duration converted into microseconds.
Sources: [packages/next/src/trace/report/to-telemetry.ts:5-27](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/trace/report/to-telemetry.ts#L5-L27)

| Trace Event Name | Mapped Telemetry Event Name | Payload Structure |
| :--- | :--- | :--- |
| `webpack-invalidated` | `WEBPACK_INVALIDATED` | `{ durationInMicroseconds: number }` |

Sources: [packages/next/src/trace/report/to-telemetry.ts:5-9](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/trace/report/to-telemetry.ts#L5-L9), [packages/next/src/trace/report/to-telemetry.ts:21-26](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/trace/report/to-telemetry.ts#L21-L26)

> [!NOTE]
> `TRACE_EVENT_ACCESSLIST` acts as an explicit allowlist: any trace event whose name is absent from the lookup map is silently ignored, preventing arbitrary internal build spans from leaking into telemetry payloads.
> Sources: [packages/next/src/trace/report/to-telemetry.ts:5-15](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/trace/report/to-telemetry.ts#L5-L15)

To coordinate multiple diagnostic sinks alongside telemetry routing, `MultiReporter` implements the `Reporter` interface. It broadcasts trace events, flush operations, and close requests concurrently to an underlying array of reporters, which includes JSON diagnostics, build JSON reports, and telemetry dispatchers.
Sources: [packages/next/src/trace/report/index.ts:7-32](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/trace/report/index.ts#L7-L32)

## User consent and CLI configuration

Next.js provides global consent controls through configuration storage and environment overrides. The `Telemetry` class constructor inspects `process.env.NEXT_TELEMETRY_DISABLED` to determine whether collection is blocked.
Sources: [packages/next/src/telemetry/storage.ts:56-70](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/telemetry/storage.ts#L56-L70)

Persistent user preferences are maintained using a configuration store initialized under the project distribution directory or cache storage.
Sources: [packages/next/src/telemetry/storage.ts:40-82](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/telemetry/storage.ts#L40-L82)

The `next telemetry` command interface handles user prompt interactions and preference modifications directly from the command line.
Sources: [packages/next/src/cli/next-telemetry.ts:14-51](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/cli/next-telemetry.ts#L14-L51)

| Command Option / Flag | Action Performed | Result Output Message |
| :--- | :--- | :--- |
| `enable` | Sets internal telemetry preference to enabled via `telemetry.setEnabled(true)` | `Success!` followed by status confirmation |
| `disable` | Sets internal telemetry preference to disabled via `telemetry.setEnabled(false)` | `Your preference has been saved to [path].` or notice that collection is already disabled |
| *none* | Displays current telemetry configuration status and explanation | `Next.js Telemetry` title followed by current status block |

Sources: [packages/next/src/cli/next-telemetry.ts:14-51](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/cli/next-telemetry.ts#L14-L51)

> [!NOTE]
> When telemetry is newly initialized without a stored notification date, the `Telemetry` constructor triggers `this.notify()` to print an informational attention message to standard output unless `skipNotify` is set to true.
> Sources: [packages/next/src/telemetry/storage.ts:61-118](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/telemetry/storage.ts#L61-L118)

## Related

- [CLI Commands](https://www.doc0.dev/docs/8f4009b0-65bd-4480-9b00-e201f0914bb3/technical/cli-telemetry/cli-commands)
- [Trace Profiling](https://www.doc0.dev/docs/8f4009b0-65bd-4480-9b00-e201f0914bb3/technical/cli-telemetry/trace-profiling)


## Sitemap

See the full [sitemap](https://www.doc0.dev/docs/8f4009b0-65bd-4480-9b00-e201f0914bb3/llms.txt) for all pages in this wiki.
