It's 2 AM. Your /api/checkout endpoint has been returning 500 errors for 47 minutes. Your external uptime monitor? It shows green. The health check endpoint returns 200 OK every 60 seconds, like nothing is wrong.

Meanwhile, 340 real checkout requests have failed. You find out the next morning from a Stripe webhook backlog and three angry customer emails.

This is the problem with external monitoring for Next.js APIs. It checks the front door. It doesn't know what's happening inside.

Why External Monitoring Falls Short for Next.js

Tools like Pingdom, UptimeRobot, and even Datadog synthetic checks work the same way: they send an HTTP request to a URL every N seconds and check if the response is 200. That's it.

For a Next.js application, this model has fundamental blind spots:

  • It only tests one endpoint at a time. If you have 15 API routes, you'd need 15 separate monitors — and most tools charge per check.
  • It misses intermittent failures. If your /api/payments fails for 3 out of every 100 requests due to a race condition, a ping every 60 seconds will never catch it.
  • It can't measure real latency. The round-trip time from Virginia to your Vercel deployment includes network latency, CDN caching, and edge routing. None of that reflects what your actual users experience.
  • It doesn't work behind firewalls. If your API is internal (B2B, microservices, admin dashboards), external pings literally can't reach it.
  • Serverless cold starts break measurements. A health check hitting a warm function measures 50ms. A real user hitting a cold function gets 1800ms. The monitor never sees the cold start.

External monitoring answers one question: "Is the server reachable?" Internal monitoring answers the question that actually matters: "Are real requests succeeding?"

The Next.js Instrumentation Hook: Built for This

Since Next.js 13.2, there's a first-party way to run code when your server starts: the instrumentation hook. You create a file called instrumentation.ts at the root of your project, and Next.js calls its register() function once during server initialization.

This is the official mechanism for observability. The Next.js docs explicitly recommend it for:

  • OpenTelemetry tracing
  • Error tracking (Sentry, Bugsnag)
  • Performance monitoring
  • Custom logging

Here's the minimal structure:

// instrumentation.ts (project root)
export async function register() {
  // This runs once when the server starts.
  // Perfect for initializing monitoring, tracing, or logging.
  console.log('Server initialized — monitoring active')
}

On Vercel, this runs once per serverless function instance. On a Node.js server, it runs once at startup. Either way, it's the right place to hook into the request lifecycle.

Building a Basic Request Monitor from Scratch

Before reaching for a tool, let's understand what internal monitoring looks like. Here's a minimal implementation using Next.js middleware to intercept every API request:

// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

export function middleware(request: NextRequest) {
  const start = Date.now()
  const response = NextResponse.next()

  // Track timing
  const duration = Date.now() - start
  const path = request.nextUrl.pathname

  // Log every API request
  if (path.startsWith('/api/')) {
console.log(JSON.stringify({
  path,
  method: request.method,
  duration,
  timestamp: new Date().toISOString(),
}))
  }

  return response
}

export const config = {
  matcher: '/api/:path*',
}

This gives you structured logs for every API request. But it's just logging — no alerting, no aggregation, no dashboards. To make this production-ready, you'd need to:

  1. Store metrics somewhere (time-series database)
  2. Calculate P50/P95/P99 latency percentiles
  3. Track error rates per endpoint
  4. Build an alerting system (Slack, email, etc.)
  5. Handle the infrastructure to run all of this

That's months of work. And you're trying to ship a product, not build a monitoring platform.

The Proper Approach: Instrumentation + Hooks

A better architecture uses the instrumentation hook to initialize monitoring and then captures data at the right level. Here's what a production setup looks like conceptually:

// instrumentation.ts
export async function register() {
  if (process.env.NEXT_RUNTIME === 'nodejs') {
// Only run on the server, not during build
const { setupMonitoring } = await import('./lib/monitoring')
setupMonitoring({
  onRequest: (data) => {
    // Called for every API request with:
    // - path, method, statusCode
    // - duration (ms)
    // - error (if any)
  },
  onError: (error, context) => {
    // Called when an unhandled error occurs
    // - error: the Error object
    // - context: { path, method, headers }
  },
})
  }
}
// lib/monitoring.ts
interface RequestData {
  path: string
  method: string
  statusCode: number
  duration: number
  error?: Error
}

interface MonitoringConfig {
  onRequest: (data: RequestData) => void
  onError: (error: Error, context: Record<string, unknown>) => void
}

export function setupMonitoring(config: MonitoringConfig) {
  // Patch the global fetch or use Node.js diagnostics_channel
  // to intercept HTTP handling at the server level.
  //
  // This is where the complexity lives:
  // - Hook into Next.js request handling
  // - Measure actual response times
  // - Capture errors without swallowing them
  // - Buffer and batch metrics for efficiency
}

The challenge is that "hook into Next.js request handling" is non-trivial. Next.js doesn't expose a simple middleware for server-side timing that includes the full response lifecycle. You'd need to patch Node.js HTTP internals or use diagnostics_channel — both of which require deep knowledge of Next.js internals and break across versions.

External vs Internal Monitoring: Side by Side

CapabilityExternal (Pingdom, UptimeRobot)Internal (Instrumentation Hook)
Monitors all API routes automaticallyNo — one monitor per URLYes — intercepts every request
Catches intermittent errorsNo — samples every N secondsYes — sees every request
Measures real user latencyNo — measures synthetic round-tripYes — measures server processing time
Works behind firewalls / VPNsNoYes
Captures cold start impactNo — hits warm instancesYes — measures every invocation
Detects errors in under 10 secondsNo — 1-5 minute check intervalsYes — real-time
Requires infrastructure to manageNo (SaaS)Depends — DIY requires infra
Setup complexityLow — paste a URLHigh (DIY) or Low (SDK)

The bottom line: external monitoring is a smoke detector in the hallway. Internal monitoring is a sensor in every room.

How Nurbak Watch Solves This in 5 Lines

Nurbak Watch is an API monitoring SDK built specifically for Next.js. It uses the instrumentation hook to run inside your server — not as an external ping.

Install it:

npm install @nurbak/watch

Add it to your instrumentation file:

// instrumentation.ts
import { initWatch } from '@nurbak/watch'

export function register() {
  initWatch({
apiKey: process.env.NURBAK_WATCH_KEY,
  })
}

That's it. Five lines. Here's what happens next:

  • Auto-discovery: Every API route in your Next.js app is detected automatically. No manual configuration, no URL list to maintain.
  • Real-time metrics: Response time, status codes, and error rates for every endpoint — not sampled, measured on every request.
  • Instant alerts: Slack, email, or WhatsApp notifications in under 10 seconds when an endpoint starts failing. Not minutes — seconds.
  • Zero infrastructure: Metrics are sent to Nurbak's cloud. No time-series database to provision, no Grafana dashboards to build.

What Nurbak Watch Tracks

For every API route, you get:

  • P50 / P95 / P99 latency — real server-side timing, not synthetic
  • Error rate — percentage of 4xx and 5xx responses
  • Throughput — requests per minute per endpoint
  • Cold start frequency — how often functions initialize (Vercel)
  • Slow endpoint detection — automatic flagging when P95 exceeds thresholds

Alerts are configurable per endpoint. You might want a Slack message when /api/checkout errors, but only an email digest for /api/analytics.

When to Use External Monitoring Too

Internal monitoring doesn't replace external monitoring — it complements it. You still want external checks for:

  • DNS resolution — verifying your domain resolves correctly from different regions
  • SSL certificate expiry — catching certificates before they expire
  • Full outages — if your server is completely down, internal monitoring can't report (because it's down too)
  • Public status pages — showing uptime to customers requires external verification

The ideal setup: Nurbak Watch internally for request-level monitoring and alerts, plus a simple external uptime check (even a free UptimeRobot ping) for total outage detection.

Getting Started

Nurbak Watch is in beta and free during launch. No credit card, no trial limits.

  1. Go to nurbak.com and create an account
  2. Run npm install @nurbak/watch
  3. Add the 5 lines to instrumentation.ts
  4. Deploy your app
  5. See every API route appear in your dashboard within 60 seconds

You'll go from zero visibility to full API monitoring in the time it takes to read this sentence twice. Your /api/checkout at 2 AM will never fail silently again.

Related Articles