Back to Blog
6/11/2026Article

nextjs error monitoring complete guide

Next.js error monitoring is more complex than most guides admit. Unlike a plain React app, a Next.js project has four distinct error surfaces — client components, server components, route handlers, and middleware — each requiring different instrumentation. This guide covers both the App Router and Pages Router, explains why client-only SDKs leave you blind to server-side failures, and walks through a complete setup including source maps and Web Vitals. Practical code examples throughout.

nextjs error monitoring complete guide

The Complete Guide to Error Monitoring in Next.js (App Router & Pages Router)

Published by Sublyzer One · 10 min read · Tags: Next.js, Error Monitoring, React, Debugging

Next.js is the default choice for production React apps in 2026. But error monitoring in Next.js is genuinely more complicated than in a plain React SPA — and most guides either cover only the Pages Router, ignore server components entirely, or assume you're using Sentry without questioning whether you should be.

This guide covers both routers, explains where errors actually originate in a Next.js app, and shows how to capture them properly — regardless of which tool you use.

Why Next.js error monitoring is different

A plain React app runs entirely in the browser. Errors happen in one place, with one runtime, and your SDK captures them with a single window.onerror listener.

Next.js is different. A single user request can touch:

  1. Server Components — rendered on the server, never in the browser
  2. Route Handlers (app/api/) — server-side API logic
  3. Middleware — runs on the Edge runtime, not Node
  4. Client Components — browser-side React
  5. Static generation (getStaticProps, generateStaticParams) — build-time Node process

An error in a Server Component produces a server log, not a browser exception. An error in Middleware might not surface at all if you're not watching for it. If your monitoring SDK only hooks into the browser, you're blind to at least half of where your app can fail.

The four error surfaces in Next.js

1. Client-side errors (both routers)

The familiar ones — unhandled JavaScript exceptions and unhandled Promise rejections in the browser. These are what most SDKs capture by default.

In the Pages Router, you also get access to _error.js / _error.tsx for custom error pages. In the App Router, error.tsx files at each route segment serve the same purpose.



tsx

ts
// app/dashboard/error.tsx
'use client'


export default function DashboardError({
  error,
  reset,
}: {
  error: Error & { digest?: string }
  reset: () => void
}) {
  // This is where you log client errors in the App Router
  useEffect(() => {
    reportError(error) // your monitoring SDK
  }, [error])


  return (
    <div>
      <h2>Something went wrong in the dashboard</h2>
      <button onClick={reset}>Try again</button>
    </div>
  )
}

The digest property is important — Next.js generates it for server errors that are sanitised before reaching the client, so you can correlate a client-visible error with the full server-side stack trace.

2. Server Component errors (App Router only)

This is the one most guides miss. Server Components run on the server and throw errors that never reach the browser as JavaScript exceptions — they get caught by the nearest error.tsx boundary, but the full stack trace only exists in your server logs.

To capture these properly, you need server-side instrumentation. Next.js 15 introduced instrumentation.ts at the root of your project for exactly this:



ts

ts
// instrumentation.ts
export async function onRequestError(
  err: Error,
  request: { path: string; method: string },
  context: { routeType: string }
) {
  // Called for every server-side error in Next.js 15+
  await reportServerError(err, { path: request.path, routeType: context.routeType })
}

If you're on Next.js 13 or 14, you don't have onRequestError — you need to wrap your Server Components manually or rely on the logging integration of your monitoring tool.

3. Route Handler errors (App Router) / API Route errors (Pages Router)

These are server-side errors in your API layer. They're easy to miss because a failed API route often returns a 500 response without throwing an uncaught exception — depending on how your error handling is structured.

The safest pattern is a wrapper:



ts

ts
// lib/with-error-handling.ts
import { NextResponse } from 'next/server'


export function withErrorHandling(
  handler: (req: Request) => Promise<NextResponse>
) {
  return async (req: Request) => {
    try {
      return await handler(req)
    } catch (err) {
      reportError(err, { url: req.url, method: req.method })
      return NextResponse.json({ error: 'Internal server error' }, { status: 500 })
    }
  }
}


// app/api/users/route.ts
export const GET = withErrorHandling(async (req) => {
  const users = await db.users.findMany()
  return NextResponse.json(users)
})

4. Middleware errors (Edge Runtime)

Middleware runs on the Edge runtime, which is not Node.js — it's a V8 isolate with a restricted API. Some monitoring SDKs don't support it at all because they depend on Node APIs that aren't available at the edge.

Check your SDK's documentation explicitly for Edge runtime support before assuming you have coverage here. If it doesn't support the edge, your middleware errors are invisible to your monitoring tool.

Setting up Sublyzer One in a Next.js app

Sublyzer's Next.js SDK covers all four error surfaces with a single install.

Installation



bash

npm
npm install @sublyzer/nextjs
# or
yarn add @sublyzer/nextjs

Configuration

Create sublyzer.config.ts at your project root:



ts

Code
import { defineConfig } from '@sublyzer/nextjs'


export default defineConfig({
  dsn: process.env.SUBLYZER_DSN,
  environment: process.env.NODE_ENV,
  release: process.env.NEXT_PUBLIC_VERCEL_GIT_COMMIT_SHA, // or your own release identifier
  tracing: {
    enabled: true,
    sampleRate: process.env.NODE_ENV === 'production' ? 0.2 : 1.0,
  },
})

Instrumentation file (Next.js 15+ / App Router)



ts

ts
// instrumentation.ts
import { SublyzerInstrumentation } from '@sublyzer/nextjs/instrumentation'


export async function register() {
  SublyzerInstrumentation.init()
}


export const onRequestError = SublyzerInstrumentation.onRequestError

Client-side initialisation



tsx

ts
// app/layout.tsx
import { SublyzerProvider } from '@sublyzer/nextjs/client'


export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html>
      <body>
        <SublyzerProvider>
          {children}
        </SublyzerProvider>
      </body>
    </html>
  )
}

That's it. The SDK hooks into client errors, Server Component errors via onRequestError, Route Handlers, and includes Edge runtime support for Middleware.

Source maps: the part everyone skips

Stack traces in production are useless without source maps. Minified code gives you errors like TypeError: e is not a function at t (main-4f3a.js:1:8234) — which tells you nothing.

Next.js generates source maps automatically in development. In production, you need to either:

Option A — Upload to your monitoring tool (recommended)

Most tools including Sublyzer accept source map uploads at deploy time:



bash

Code
# In your CI/CD pipeline, after next build
npx @sublyzer/cli upload-sourcemaps \
  --release $COMMIT_SHA \
  --dir .next/static

Add this to your next.config.js to generate source maps in production builds:



js

ts
// next.config.js
module.exports = {
  productionBrowserSourceMaps: true,
}

Option B — Hidden source maps

Generate source maps but don't serve them publicly. They stay on your server and your monitoring tool reads them server-side. More secure, slightly more complex to configure.

Without source maps, your error monitoring is technically working but practically much harder to act on.

Performance monitoring in Next.js

Errors are one signal. Performance degradation is another — and often the earlier warning.

Next.js exposes the reportWebVitals function for Pages Router apps:



ts

ts
// pages/_app.tsx
export function reportWebVitals(metric: NextWebVitalsMetric) {
  // LCP, FID, CLS, TTFB, FCP
  reportPerformanceMetric(metric)
}

In the App Router, you use the useReportWebVitals hook:



tsx

ts
// app/components/web-vitals.tsx
'use client'
import { useReportWebVitals } from 'next/web-vitals'


export function WebVitals() {
  useReportWebVitals((metric) => {
    reportPerformanceMetric(metric)
  })
  return null
}

Sublyzer captures Web Vitals automatically when you include the SublyzerProvider — no separate setup needed.

Common mistakes to avoid

Using console.error as your monitoring strategy. It works locally. In production, those logs go to your hosting provider's log drain and are gone after 7 days. You lose the aggregation, grouping, and alerting that make monitoring useful.

Only instrumenting the client. As covered above, Server Components, Route Handlers, and Middleware are outside the browser. Client-only SDKs give you a false sense of coverage.

Ignoring the digest property on errors. When Next.js catches a server error and passes it to an error.tsx boundary, it sanitises the message for security but includes a digest string. Your monitoring tool should correlate that digest with the full server-side trace — otherwise you see the error on the client but can't find the cause on the server.

Not testing your error boundaries. It's easy to set up monitoring and assume it works. Deliberately throw an error in development and verify it appears in your dashboard before you rely on it in production.

Summary

Error surfacePages RouterApp RouterWhat to use

Client JS errors

_error.tsx + SDK

error.tsx + SDK

Browser SDK

Server Component errors

N/A

instrumentation.ts

onRequestError

API / Route Handler errors

Try/catch wrapper

Try/catch wrapper

Server SDK

Middleware errors

Edge SDK (if supported)

Edge SDK (if supported)

Check SDK docs

Performance (Web Vitals)

reportWebVitals

useReportWebVitals

SDK or manual

Next.js gives you a lot of surface area to monitor. The good news is that with the right SDK and a proper instrumentation.ts setup, all of it can flow into a single dashboard — so when something breaks at 2am, you're not piecing together server logs, browser exceptions, and performance graphs from three different tools.

Sublyzer One covers all four error surfaces in Next.js — client, server, edge, and API — plus performance monitoring and AI-powered fix suggestions, in a single platform. See the Next.js integration docs →

Static HTML for crawlers: https://www.sublyzer.com/blog/nextjs-error-monitoring-complete-guide