NextjsInstrumentation & Observability

Instrumentation & Observability

Note
This is a more advanced, production-oriented feature. If you're still learning the fundamentals of the App Router, it's fine to skip this page and come back once you actually need to wire up monitoring for a deployed app.

Instrumentation is the practice of adding monitoring and tracing code to an application so you can observe what it's actually doing in production — which requests are slow, which are erroring, and why. Next.js gives this a first-class, framework-level hook rather than leaving it to ad-hoc setup scattered across your codebase.

The instrumentation.ts convention

A file named instrumentation.ts (or .js) at the root of your project — next to your app/ directory, not inside it — is picked up automatically by Next.js. If it exports a register() function, that function runs exactly once, when a new server instance starts, before any route handles a request.

TSX
// instrumentation.ts
export async function register() {
  if (process.env.NEXT_RUNTIME === 'nodejs') {
    // Set up tracing/monitoring that needs to run once, at boot
    const { init } = await import('./monitoring')
    init()
  }
}

Because it runs once at startup rather than per-request, instrumentation.ts is the right place for expensive, one-time setup work — initializing a tracing SDK, opening a long-lived connection, or registering global error handlers — that would be wasteful or incorrect to repeat on every request.

Typical use cases
  • Initializing an error-tracking SDK such as Sentry so uncaught exceptions are automatically reported.

  • Setting up OpenTelemetry tracing/exporters so requests can be followed across your app and downstream services.

  • Registering custom metrics or logging pipelines that need a single startup call rather than per-request initialization.

TSX
// instrumentation.ts
import * as Sentry from '@sentry/nextjs'

export async function register() {
  Sentry.init({
    dsn: process.env.SENTRY_DSN,
    tracesSampleRate: 1.0,
  })
}
Capturing errors with onRequestError

instrumentation.ts can also export an onRequestError hook, which Next.js calls whenever an error is thrown while handling a request on the server — a good central place to forward errors to your monitoring provider with request context attached.

TSX
// instrumentation.ts
export async function onRequestError(err, request, context) {
  await fetch('https://monitoring.example.com/report', {
    method: 'POST',
    body: JSON.stringify({ err, url: request.url, context }),
  })
}
Where it fits alongside other runtimes

Environment

register() runs

Node.js server runtime

Once per server instance, at startup

Edge runtime

Once per Edge worker instance, at startup

Browser

Never — instrumentation.ts is server-only code

Warning
Check process.env.NEXT_RUNTIME before importing Node.js-specific tooling (like most tracing SDKs) inside register() — instrumentation.ts also runs in the Edge runtime if you deploy edge routes, and Node-only imports will fail there.
Tip
If you're only trying to log page-level analytics or Core Web Vitals from the browser, you want useReportWebVitals in a Client Component, not instrumentation.ts — this file is exclusively for server-side, startup-time setup.