Skip to content

Next.js integration guide

View Markdown

Typical installation time: 7 minutes

Hi there! You’ve found Honeybadger’s guide to Next.js error and exception tracking. Once installed, Honeybadger will automatically report errors from your Next.js application.

The @honeybadger-io/nextjs package builds on @honeybadger-io/js to provide a simplified integration for Next.js applications. It hooks into Next.js through its instrumentation and instrumentation-client file conventions, so it works the same way with Turbopack and webpack. You can always refer to the @honeybadger-io/js documentation for more information and advanced configuration.

  • Automatic reporting of server errors via Next.js’s onRequestError hook, including Server Components, Route Handlers, Server Actions, middleware, and Pages Router API routes
  • Client-side error reporting, configured before React hydrates
  • Breadcrumbs, including App Router navigations
  • Request, correlation, and trace IDs on every server error, matching the request.handled Insights event for the same request
  • Source map upload after every production build
  • CLI command to generate the Honeybadger instrumentation and configuration files
  • Next.js 15.4 or later
  • Node.js 20.9 or later
  • Turbopack or webpack (both are supported)
  • The Node.js runtime. The edge runtime is not supported (see Edge runtime).

Add @honeybadger-io/nextjs and @honeybadger-io/js as dependencies. The examples on this page import Honeybadger from @honeybadger-io/js directly, so add it explicitly rather than relying on it being installed as a transitive dependency:

# npm
npm add @honeybadger-io/js @honeybadger-io/nextjs --save
# yarn
yarn add @honeybadger-io/js @honeybadger-io/nextjs

Run the following command in your project root:

npx honeybadger-copy-config-files

The following files will be added to your project:

  • honeybadger.server.config.js - Honeybadger configuration for the Next.js server. Always created in the project root.
  • instrumentation.[js|ts] - Loads the server configuration when the server starts and reports server errors to Honeybadger through onRequestError
  • instrumentation-client.[js|ts] - Configures Honeybadger in the browser before React hydrates, and records App Router navigations as breadcrumbs
  • pages/_error.js - Pages Router custom error component, if a pages directory exists
  • app/error.[js|tsx] - App Router error component, if an app directory exists
  • app/global-error.[js|tsx] - App Router global error component, if an app directory exists

The instrumentation files are written where Next.js looks for them: the project root, or src/ when your pages (or app) directory lives in src/. honeybadger.server.config.js always stays in the project root, so when the instrumentation files are in src/, the script changes their imports to ../honeybadger.server.config. Keep that in mind when you copy the examples on this page, which assume the instrumentation files are in the project root.

Note: The script replaces an existing honeybadger.server.config.js without a backup, so commit or copy it first if you’ve customized it. Existing error components are backed up to .bak files before they’re replaced.

Note: The script never overwrites an existing instrumentation or instrumentation-client file, since other tools may register hooks there. Instead, it prints a message and leaves the file alone. Add the Honeybadger parts shown below to your existing files by hand.

The generated instrumentation file configures Honeybadger on the server and reports server errors:

instrumentation.js
import { captureRequestError } from "@honeybadger-io/nextjs";
export async function register() {
// Use "../honeybadger.server.config" if this file is in src/
await import("./honeybadger.server.config");
}
export const onRequestError = captureRequestError;

The generated instrumentation-client file configures Honeybadger in the browser:

instrumentation-client.js
import Honeybadger from "@honeybadger-io/js";
import { captureRouterTransitionStart } from "@honeybadger-io/nextjs";
export const config = {
apiKey: process.env.NEXT_PUBLIC_HONEYBADGER_API_KEY,
environment:
process.env.NEXT_PUBLIC_VERCEL_ENV ||
process.env.VERCEL_ENV ||
process.env.NODE_ENV,
revision: process.env.NEXT_PUBLIC_HONEYBADGER_REVISION,
};
Honeybadger.configure(config);
// App Router only: records navigations as breadcrumbs
export const onRouterTransitionStart = captureRouterTransitionStart;

onRouterTransitionStart is an App Router hook. If you only use the Pages Router, you can remove it.

Wrap your Next.js config with withHoneybadgerConfig. It adds @honeybadger-io/js to serverExternalPackages and uploads source maps to Honeybadger after each production build:

next.config.ts
import type { NextConfig } from "next";
import {
withHoneybadgerConfig,
type HoneybadgerNextJsConfig,
} from "@honeybadger-io/nextjs";
const nextConfig: NextConfig = {
// ... your existing Next.js config
};
const honeybadgerConfig: HoneybadgerNextJsConfig = {
// Required to upload source maps to Honeybadger
apiKey: process.env.NEXT_PUBLIC_HONEYBADGER_API_KEY,
assetsUrl: process.env.NEXT_PUBLIC_HONEYBADGER_ASSETS_URL,
revision: process.env.NEXT_PUBLIC_HONEYBADGER_REVISION,
};
export default withHoneybadgerConfig(nextConfig, honeybadgerConfig);

If you use next.config.js:

next.config.js
const { withHoneybadgerConfig } = require("@honeybadger-io/nextjs");
/** @type {import('next').NextConfig} */
const nextConfig = {
// ... your existing Next.js config
};
module.exports = withHoneybadgerConfig(nextConfig, {
apiKey: process.env.NEXT_PUBLIC_HONEYBADGER_API_KEY,
assetsUrl: process.env.NEXT_PUBLIC_HONEYBADGER_ASSETS_URL,
revision: process.env.NEXT_PUBLIC_HONEYBADGER_REVISION,
});

Note: The value of assetsUrl should be the URL to your domain suffixed with _next. For example, if your app is deployed on Vercel and has the domain my-app.vercel.app, the value of assetsUrl should be https://my-app.vercel.app/_next.

All options are optional:

OptionDescription
apiKeyYour Honeybadger API key. Required to upload source maps. Defaults to the NEXT_PUBLIC_HONEYBADGER_API_KEY environment variable.
assetsUrlThe public URL of your build output, such as https://example.com/_next. Required to upload source maps. Defaults to the NEXT_PUBLIC_HONEYBADGER_ASSETS_URL environment variable.
revisionThe revision of the current deployment. It must match the revision in your Honeybadger configuration for source maps to apply. Defaults to the NEXT_PUBLIC_HONEYBADGER_REVISION environment variable.
endpointThe source map upload endpoint. Default: https://api.honeybadger.io/v1/source_maps.
silentHide informational build messages. Warnings and errors are always shown. Default: true.
ignoreErrorsLog a failed upload instead of failing the build. Default: false.
ignorePathsGlob patterns for JavaScript files whose source maps should not be uploaded. Patterns match the file’s name, not its path: main.js and **/main.js work, while static/chunks/*.js never matches. Default: [].
developmentEnvironmentsNODE_ENV values for which the upload is skipped. Default: ["dev", "development", "test"].
retriesNumber of times to retry a failed upload. Default: 3.
workerCountNumber of source maps to upload in parallel. Default: 5.
deploySend a deploy notification after the source maps are uploaded. See Tracking deploys.
disableSourceMapUploadTurn off source map upload without removing the rest of the configuration. Default: false.

onRequestError and the generated error components work together. Keep both:

Where the error happensReported by
Server Components, generateMetadataonRequestError in instrumentation
Route HandlersonRequestError in instrumentation
Server ActionsonRequestError in instrumentation
MiddlewareonRequestError in instrumentation
Client Component renderingapp/error.[js|tsx] and app/global-error.[js|tsx]
Browser event handlers and other client codeThe browser client configured in instrumentation-client

Errors reported by onRequestError include the real error, even in production where Next.js sends only a generic message and a digest to the browser. Each report includes path, method, router_kind, route_path, and route_type (which tells you whether the error came from a page render, a Route Handler, a Server Action, or middleware), along with request_id, correlation_id, and, when an OpenTelemetry span is active, trace_id and span_id.

The errors that Next.js uses for control flow (redirect(), notFound(), forbidden(), and unauthorized()) are not reported.

Route Handlers need no wrapper. Errors thrown in them are reported by onRequestError:

app/api/hello/route.ts
import { NextResponse } from "next/server";
export async function GET() {
// An error thrown here is reported to Honeybadger automatically
return NextResponse.json({ message: "hello" });
}

With the Pages Router, onRequestError reports server errors from page rendering, data fetching methods such as getServerSideProps, API routes, and middleware. API routes need no wrapper.

The generated pages/_error.js component reports client-side errors only. Server errors are already reported by onRequestError, so reporting them again there would duplicate them.

As of version 6, @honeybadger-io/nextjs does not support the edge runtime. Next.js recommends the Node.js runtime, which is the default.

  • Remove export const runtime = "edge" from Route Handlers and pages so they run on the Node.js runtime.
  • Run middleware on the Node.js runtime. In Next.js 16, proxy.ts always runs on Node.js. In Next.js 15.5, add runtime: "nodejs" to your middleware’s config export.

If you need the edge runtime, stay on version 5.x of @honeybadger-io/nextjs.

Honeybadger can record a request.handled Insights event for every request, including successful ones, with the method, path, status, duration, request_id, correlation_id, trace_id, and span_id. Next.js emits this request data as OpenTelemetry spans, so Insights request events need @vercel/otel and @opentelemetry/api:

npm install @vercel/otel @opentelemetry/api

Make sure Insights HTTP instrumentation is enabled in your server config (the generated file already enables it):

honeybadger.server.config.js
import Honeybadger from "@honeybadger-io/js";
export const config = {
apiKey: process.env.NEXT_PUBLIC_HONEYBADGER_API_KEY,
environment:
process.env.NEXT_PUBLIC_VERCEL_ENV ||
process.env.VERCEL_ENV ||
process.env.NODE_ENV,
revision: process.env.NEXT_PUBLIC_HONEYBADGER_REVISION,
insights: { enabled: true, http: true },
};
Honeybadger.configure(config);

Then call registerHoneybadgerInsights() from register():

instrumentation.js
import {
captureRequestError,
registerHoneybadgerInsights,
} from "@honeybadger-io/nextjs";
export async function register() {
// Use "../honeybadger.server.config" if this file is in src/
await import("./honeybadger.server.config");
await registerHoneybadgerInsights();
}
export const onRequestError = captureRequestError;

registerHoneybadgerInsights() accepts an optional serviceName (defaults to the NEXT_PUBLIC_HONEYBADGER_SERVICE_NAME environment variable, or nextjs-app) and attributesFromHeaders for additional request headers to record on the span.

If you already call registerOTel() yourself, don’t call registerHoneybadgerInsights(), since registering OpenTelemetry twice competes for the global provider. Add Honeybadger’s span processor and header attributes to your existing call instead:

instrumentation.js
import { registerOTel } from "@vercel/otel";
import {
captureRequestError,
honeybadgerSpanProcessor,
HONEYBADGER_HEADER_ATTRIBUTES,
} from "@honeybadger-io/nextjs";
export async function register() {
// Use "../honeybadger.server.config" if this file is in src/
await import("./honeybadger.server.config");
registerOTel({
serviceName: "my-app",
attributesFromHeaders: { ...HONEYBADGER_HEADER_ATTRIBUTES },
spanProcessors: [honeybadgerSpanProcessor()],
});
}
export const onRequestError = captureRequestError;

request_id and correlation_id are read from the x-request-id, request-id, x-correlation-id, and x-amzn-trace-id request headers. When none are present, they fall back to the OpenTelemetry span and trace IDs. Errors reported by onRequestError use the same IDs, so you can join an error to the Insights events of the request it happened in.

These IDs are not added to the event context, so events you send yourself with Honeybadger.event(...) don’t include them automatically. See Context on the server.

For the full Insights configuration surface (including console logs, filtering, and sampling), see Automatic instrumentation.

The above configuration will automatically report errors to Honeybadger in most cases, but you can also report errors manually, from both server and client code:

import Honeybadger from "@honeybadger-io/js";
Honeybadger.notify(error);

In server code, use await Honeybadger.notifyAsync(error) if you need to make sure the error is sent before the function returns.

Honeybadger can track which users have encountered each error. To identify the current user in error reports from client code, add a user identifier and/or email address with Honeybadger.setContext:

import Honeybadger from "@honeybadger-io/js";
Honeybadger.setContext({
user_id: 123,
user_email: "user@example.com",
});

setContext is shared across requests on the server, so use it only in client code. In server code, pass the user with each report instead. See Context on the server.

Sometimes additional application state may be helpful for diagnosing errors. In client code, you can arbitrarily specify additional key/value pairs when you invoke setContext.

import Honeybadger from "@honeybadger-io/js";
Honeybadger.setContext({
active_organization: 55,
custom_configuration: false,
});

If your user logs out or if your context changes during the React component lifetime, you can set new values as appropriate by invoking setContext again.

Additionally, if needed, you can clear the context by invoking clear:

import Honeybadger from "@honeybadger-io/js";
// Set the context to {}
Honeybadger.clear();

setContext and setEventContext are best suited to client code, where each browser has its own Honeybadger client. On the server, context isn’t isolated per request: it’s shared by every request handled by the same server process, so values set during one request can leak into another. In server code, pass request-specific data directly instead:

import Honeybadger from "@honeybadger-io/js";
Honeybadger.notify(error, { context: { user_id: user.id } });
Honeybadger.event("order.created", { order_id: order.id, user_id: user.id });

@honeybadger-io/nextjs is built on @honeybadger-io/js.

See the Honeybadger JavaScript integration documentation for additional customization options.

Honeybadger can automatically un-minify your code if you provide a source map along with your minified JavaScript files. See our Source Map Guide for details.

Once apiKey and assetsUrl are set (in withHoneybadgerConfig or through the NEXT_PUBLIC_HONEYBADGER_API_KEY and NEXT_PUBLIC_HONEYBADGER_ASSETS_URL environment variables), source maps are uploaded automatically after every production build, with both Turbopack and webpack. If either value is missing, the upload is skipped with a warning and the build continues.

Next.js doesn’t emit source maps for production builds by default. When source map upload is configured, withHoneybadgerConfig turns them on for you:

Next.js optionCoversEmitted to
productionBrowserSourceMapsThe browser build.next/static, which is served publicly
experimental.serverSourceMapsThe server build.next/server, which is not served

After uploading, the browser source maps are deleted from the build output so they aren’t served to visitors. Server source maps are left in place, since they aren’t served and Next.js uses them to format server-side stack traces.

If you set either option yourself, your setting is left as is. In particular, if you set productionBrowserSourceMaps: true, your browser source maps are uploaded but not deleted.

A failed upload fails the build. Set ignoreErrors: true if you’d rather log the failure and continue.

You can notify Honeybadger when you’ve deployed a new build. Honeybadger will associate an error report with a specific revision number (matching the revision field in the configuration passed to Honeybadger.configure). Set deploy information under the deploy key in your withHoneybadgerConfig options:

withHoneybadgerConfig(nextConfig, {
apiKey: process.env.NEXT_PUBLIC_HONEYBADGER_API_KEY,
assetsUrl: process.env.NEXT_PUBLIC_HONEYBADGER_ASSETS_URL,
revision: process.env.NEXT_PUBLIC_HONEYBADGER_REVISION,
deploy: {
environment:
process.env.NEXT_PUBLIC_VERCEL_ENV ||
process.env.VERCEL_ENV ||
process.env.NODE_ENV,
repository: "https://url.to.git.repository",
localUsername: "username",
},
});

The deploy notification is sent only after source maps were uploaded.

When an error occurs in the browser, a form can be shown to gather feedback from your users. To show the form for every error reported from the browser, add an afterNotify handler in instrumentation-client. Feedback is linked to the last error reported successfully, so only show the form when the report succeeded:

instrumentation-client.js
Honeybadger.configure(config);
Honeybadger.afterNotify((err) => {
if (!err) Honeybadger.showUserFeedbackForm();
});

Read more about this feature here.

The following limitations are known to exist and will be tackled in future releases:

  • Issue link: Server-side stack frames are not un-minified yet. Browser stack frames are.
  • The edge runtime is not supported. See Edge runtime.
  • Issue link: Context set with setContext or setEventContext on the server is not isolated per request. See Context on the server.

Version 6 of @honeybadger-io/nextjs replaces the webpack-based setup with Next.js’s instrumentation hooks, which is what makes it work with Turbopack, the default bundler since Next.js 16. To upgrade:

  1. Make sure you’re on Next.js 15.4 or later and Node.js 20.9 or later, and that your app runs on the Node.js runtime. If you can’t upgrade yet, or you need the edge runtime, stay on version 5.x of @honeybadger-io/nextjs.

  2. Update the packages:

    npm add @honeybadger-io/nextjs@latest @honeybadger-io/js@latest

    @honeybadger-io/nextjs no longer depends on @honeybadger-io/react, so you can remove @honeybadger-io/react from your dependencies unless you use it directly.

  3. Replace setupHoneybadger with withHoneybadgerConfig in your next.config.js, and move the options that were under webpackPluginOptions to the top level:

    next.config.js
    const { setupHoneybadger } = require("@honeybadger-io/nextjs");
    const { withHoneybadgerConfig } = require("@honeybadger-io/nextjs");
    module.exports = setupHoneybadger(moduleExports, {
    module.exports = withHoneybadgerConfig(moduleExports, {
    disableSourceMapUpload: false,
    silent: true,
    webpackPluginOptions: {
    apiKey: process.env.NEXT_PUBLIC_HONEYBADGER_API_KEY,
    assetsUrl: process.env.NEXT_PUBLIC_HONEYBADGER_ASSETS_URL,
    revision: process.env.NEXT_PUBLIC_HONEYBADGER_REVISION,
    },
    apiKey: process.env.NEXT_PUBLIC_HONEYBADGER_API_KEY,
    assetsUrl: process.env.NEXT_PUBLIC_HONEYBADGER_ASSETS_URL,
    revision: process.env.NEXT_PUBLIC_HONEYBADGER_REVISION,
    });

    If you set devtool: "hidden-source-map" or productionBrowserSourceMaps yourself for Honeybadger, remove it. withHoneybadgerConfig now handles source maps for you (see Source map upload and tracking deploys).

  4. Commit or copy your honeybadger.server.config.js, then run npx honeybadger-copy-config-files again to generate the instrumentation and instrumentation-client files and the updated error components. The script replaces honeybadger.server.config.js without a backup, so copy your custom settings back afterwards. Existing error components are backed up to .bak files. If you already have an instrumentation or instrumentation-client file, add the Honeybadger parts shown above to it by hand.

  5. In honeybadger.server.config.js, remove the projectRoot setting and the beforeNotify handler that rewrote backtrace paths. They’re no longer needed.

  6. Delete honeybadger.browser.config.js (listed as honeybadger.client.config.js in earlier versions of this guide) and honeybadger.edge.config.js. Move any custom browser settings to instrumentation-client.

  7. Move any Route Handlers, pages, and middleware that use the edge runtime to the Node.js runtime (see Edge runtime). Code that stays on the edge runtime is not supported.

  8. Remove withHoneybadger from your Route Handlers, API routes, and middleware, along with any imports of the Honeybadger config files there. onRequestError now reports their errors. If you used withHoneybadger for Insights request events, follow Insights instrumentation instead.

  9. Import Honeybadger from @honeybadger-io/js instead of @honeybadger-io/react in your own code, as shown in the examples on this page.

Two sample applications are available in the examples folder. Follow the README instructions to run them.