Next.js integration guide
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.
Features
Section titled “Features”- Automatic reporting of server errors via Next.js’s
onRequestErrorhook, 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.handledInsights event for the same request - Source map upload after every production build
- CLI command to generate the Honeybadger instrumentation and configuration files
Requirements
Section titled “Requirements”- 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).
Installation
Section titled “Installation”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:
# npmnpm add @honeybadger-io/js @honeybadger-io/nextjs --save
# yarnyarn add @honeybadger-io/js @honeybadger-io/nextjsConfiguration
Section titled “Configuration”Generate the configuration files
Section titled “Generate the configuration files”Run the following command in your project root:
npx honeybadger-copy-config-filesThe 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 throughonRequestErrorinstrumentation-client.[js|ts]- Configures Honeybadger in the browser before React hydrates, and records App Router navigations as breadcrumbspages/_error.js- Pages Router custom error component, if apagesdirectory existsapp/error.[js|tsx]- App Router error component, if anappdirectory existsapp/global-error.[js|tsx]- App Router global error component, if anappdirectory 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:
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:
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 breadcrumbsexport const onRouterTransitionStart = captureRouterTransitionStart;onRouterTransitionStart is an App Router hook. If you only use the Pages
Router, you can remove it.
Configure next.config
Section titled “Configure next.config”Wrap your Next.js config with withHoneybadgerConfig. It adds
@honeybadger-io/js to serverExternalPackages and uploads source maps to
Honeybadger after each production build:
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:
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:
| Option | Description |
|---|---|
apiKey | Your Honeybadger API key. Required to upload source maps. Defaults to the NEXT_PUBLIC_HONEYBADGER_API_KEY environment variable. |
assetsUrl | The 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. |
revision | The 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. |
endpoint | The source map upload endpoint. Default: https://api.honeybadger.io/v1/source_maps. |
silent | Hide informational build messages. Warnings and errors are always shown. Default: true. |
ignoreErrors | Log a failed upload instead of failing the build. Default: false. |
ignorePaths | Glob 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: []. |
developmentEnvironments | NODE_ENV values for which the upload is skipped. Default: ["dev", "development", "test"]. |
retries | Number of times to retry a failed upload. Default: 3. |
workerCount | Number of source maps to upload in parallel. Default: 5. |
deploy | Send a deploy notification after the source maps are uploaded. See Tracking deploys. |
disableSourceMapUpload | Turn off source map upload without removing the rest of the configuration. Default: false. |
App Router
Section titled “App Router”What gets reported
Section titled “What gets reported”onRequestError and the generated error components work together. Keep both:
| Where the error happens | Reported by |
|---|---|
Server Components, generateMetadata | onRequestError in instrumentation |
| Route Handlers | onRequestError in instrumentation |
| Server Actions | onRequestError in instrumentation |
| Middleware | onRequestError in instrumentation |
| Client Component rendering | app/error.[js|tsx] and app/global-error.[js|tsx] |
| Browser event handlers and other client code | The 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
Section titled “Route Handlers”Route Handlers need no wrapper. Errors thrown in them are reported by
onRequestError:
import { NextResponse } from "next/server";
export async function GET() { // An error thrown here is reported to Honeybadger automatically return NextResponse.json({ message: "hello" });}Pages Router
Section titled “Pages Router”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.
Edge runtime
Section titled “Edge runtime”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.tsalways runs on Node.js. In Next.js 15.5, addruntime: "nodejs"to your middleware’sconfigexport.
If you need the edge runtime, stay on version 5.x of @honeybadger-io/nextjs.
Insights instrumentation
Section titled “Insights instrumentation”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/apiMake sure Insights HTTP instrumentation is enabled in your server config (the generated file already enables it):
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():
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:
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.
Reporting errors
Section titled “Reporting errors”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.
Identifying users
Section titled “Identifying users”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.
Sending additional context
Section titled “Sending additional context”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,});Clearing context
Section titled “Clearing context”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();Context on the server
Section titled “Context on the server”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 });Advanced usage
Section titled “Advanced usage”@honeybadger-io/nextjs is built on
@honeybadger-io/js.
See the Honeybadger JavaScript integration documentation for additional customization options.
Source map upload and tracking deploys
Section titled “Source map upload and tracking deploys”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 option | Covers | Emitted to |
|---|---|---|
productionBrowserSourceMaps | The browser build | .next/static, which is served publicly |
experimental.serverSourceMaps | The 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.
Tracking deploys
Section titled “Tracking deploys”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.
Collect user feedback
Section titled “Collect user feedback”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:
Honeybadger.configure(config);
Honeybadger.afterNotify((err) => { if (!err) Honeybadger.showUserFeedbackForm();});Read more about this feature here.
Limitations
Section titled “Limitations”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
setContextorsetEventContexton the server is not isolated per request. See Context on the server.
Upgrading from version 5
Section titled “Upgrading from version 5”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:
-
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. -
Update the packages:
npm add @honeybadger-io/nextjs@latest @honeybadger-io/js@latest@honeybadger-io/nextjsno longer depends on@honeybadger-io/react, so you can remove@honeybadger-io/reactfrom your dependencies unless you use it directly. -
Replace
setupHoneybadgerwithwithHoneybadgerConfigin yournext.config.js, and move the options that were underwebpackPluginOptionsto 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"orproductionBrowserSourceMapsyourself for Honeybadger, remove it.withHoneybadgerConfignow handles source maps for you (see Source map upload and tracking deploys). -
Commit or copy your
honeybadger.server.config.js, then runnpx honeybadger-copy-config-filesagain to generate theinstrumentationandinstrumentation-clientfiles and the updated error components. The script replaceshoneybadger.server.config.jswithout a backup, so copy your custom settings back afterwards. Existing error components are backed up to.bakfiles. If you already have aninstrumentationorinstrumentation-clientfile, add the Honeybadger parts shown above to it by hand. -
In
honeybadger.server.config.js, remove theprojectRootsetting and thebeforeNotifyhandler that rewrote backtrace paths. They’re no longer needed. -
Delete
honeybadger.browser.config.js(listed ashoneybadger.client.config.jsin earlier versions of this guide) andhoneybadger.edge.config.js. Move any custom browser settings toinstrumentation-client. -
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.
-
Remove
withHoneybadgerfrom your Route Handlers, API routes, and middleware, along with any imports of the Honeybadger config files there.onRequestErrornow reports their errors. If you usedwithHoneybadgerfor Insights request events, follow Insights instrumentation instead. -
Import
Honeybadgerfrom@honeybadger-io/jsinstead of@honeybadger-io/reactin your own code, as shown in the examples on this page.
Sample applications
Section titled “Sample applications”Two sample applications are available in the examples folder. Follow the README instructions to run them.