Instrumentation & Observability
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.
// 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.
// 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.
// 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 |