Next.js lançou instrumentation.ts na versão 13.4 e estabilizou na 15. É a forma oficial e suportada de acoplar código de monitoramento ao seu servidor Next.js. Se você está colocando Next.js em produção e não usa, ou está sem telemetria ou está pagando por um setup mais complicado do que precisa.
O que é instrumentation.ts
instrumentation.ts é um arquivo especial que mora na raiz do seu projeto Next.js. Next.js procura por ele no boot do servidor e chama sua função register exportada uma única vez, antes de qualquer request ser tratado.
// instrumentation.ts
export async function register() {
// Isso roda uma vez, no server, no boot
}Esse é todo o contrato. O que você colocar em register() roda no runtime do server antes do tráfego chegar nas suas rotas. É o lugar certo pra inicializar SDKs de monitoramento, registrar instrumentações OpenTelemetry, configurar loggers, e validar configuração de ambiente antes de servir tráfego.
Como habilitar
No Next.js 15 está habilitado por padrão. Só crie o arquivo na raiz do projeto:
// instrumentation.ts
export async function register() {
console.log('Server booted at', new Date().toISOString())
}O que você pode interceptar
Padrão 1: Auto-instrumentação OpenTelemetry
// instrumentation.ts
export async function register() {
if (process.env.NEXT_RUNTIME === 'nodejs') {
const { registerOTel } = await import('@vercel/otel')
registerOTel({ serviceName: 'my-nextjs-app' })
}
}O dynamic import é intencional, garante que módulos só-Node não sejam bundleados pro runtime Edge.
Padrão 2: Error tracking com onRequestError
Next.js 15 adicionou um export onRequestError. Esse hook dispara quando um erro server-side é lançado de um route handler, server action, server component ou middleware.
export async function onRequestError(err, request, context) {
console.error('Server error:', {
path: request.path,
route: context.routePath,
message: err.message,
})
}Construindo um hook básico de monitoramento manualmente
// instrumentation.ts
export async function register() {
console.log('Monitoring initialized')
}
export async function onRequestError(err, request, context) {
const payload = {
timestamp: new Date().toISOString(),
message: err.message,
stack: err.stack,
route: context.routePath,
method: request.method,
}
fetch(process.env.MONITORING_WEBHOOK_URL!, {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: JSON.stringify(payload),
}).catch(() => {})
}Cerca de 20 linhas. Não é elegante (sem grouping, rate limiting, dashboards, nem alerting) mas funciona.
Por que uma ferramenta dedicada economiza tempo
O exemplo mínimo funciona para "erros caem num webhook". No momento que você quer qualquer uma destas coisas, o line count explode: agrupamento de erros, rate limiting, dashboards, cálculo de P50/P95/P99, alerting (Slack, email, WhatsApp), checks de uptime externos, monitoramento multi-região, suporte a source maps. Cada um é de alguns dias a uma semana de trabalho de engenharia.
Exemplo com OpenTelemetry
// instrumentation.ts
import { registerOTel } from '@vercel/otel'
export function register() {
registerOTel({ serviceName: 'my-nextjs-app' })
}Isso registra o OpenTelemetry no seu servidor, então cada request às suas rotas gera spans com duração e status. O destino dos dados é configurado com as variáveis de ambiente padrão OTEL_EXPORTER_OTLP_*, então você pode enviá-los para qualquer backend compatível com OTel. Combine com um handler onRequestError para tracking de erros (Sentry, ou a versão manual acima) e um check externo de uptime para quedas totais.
Erros comuns
- Importar módulos Node no topo do arquivo. Use dynamic
await import()guardado porprocess.env.NEXT_RUNTIME === 'nodejs'. - Fazer trabalho async que bloqueia register(). Deixa cold starts mais lentos.
- Deixar o monitoramento lançar exceções. Embrulhe em try/catch.
- Esquecer onRequestError. register roda uma vez, onRequestError roda por erro.
- Enviar PII em payloads de erro. Limpe cookies, auth headers e bodies antes de forwardar externamente.
Conclusão
instrumentation.ts é a resposta certa para monitoramento Next.js. Substitui os APM agents tradicionais, funciona em serverless e te dá um único lugar pra conectar tudo. Se suas necessidades são simples, construa manual em 20-50 linhas. Se precisa de algo além de reporte básico de erros, use uma ferramenta dedicada.
