Error monitoring for Next.js.

With @sentry/nextjs, Fehlo captures errors from the browser, server components, route handlers and middleware. The manual setup is five files.

As of 21 October 2026, @sentry/nextjs 11.8.0, Next.js 14 to 16 with the App Router.

1. Install the package

Terminal
npm install @sentry/nextjs

The wizard npx @sentry/wizard -i nextjs signs in to the target server, and we have not tested it with Fehlo. The manual setup takes five files, all in the project root or in src/.

2. Browser

instrumentation-client.ts
import * as Sentry from "@sentry/nextjs";

Sentry.init({
  dsn: "https://<key>@app.fehlo.de/<project-id>",
  dataCollection: {
    userInfo: false,
  },
});

export const onRouterTransitionStart = Sentry.captureRouterTransitionStart;

The onRouterTransitionStart export measures client-side navigations.

3. Server and edge

The same configuration for the Node.js and the edge runtime:

sentry.server.config.ts
import * as Sentry from "@sentry/nextjs";

Sentry.init({
  dsn: "https://<key>@app.fehlo.de/<project-id>",
  dataCollection: {
    userInfo: false,
  },
});
sentry.edge.config.ts
import * as Sentry from "@sentry/nextjs";

Sentry.init({
  dsn: "https://<key>@app.fehlo.de/<project-id>",
  dataCollection: {
    userInfo: false,
  },
});

Next.js loads them through instrumentation.ts. onRequestError reports errors from server components, route handlers and middleware.

instrumentation.ts
import * as Sentry from "@sentry/nextjs";

export async function register() {
  if (process.env.NEXT_RUNTIME === "nodejs") {
    await import("./sentry.server.config");
  }

  if (process.env.NEXT_RUNTIME === "edge") {
    await import("./sentry.edge.config");
  }
}

export const onRequestError = Sentry.captureRequestError;

4. Rendering errors

Errors that break rendering of the whole app are caught by app/global-error.tsx:

app/global-error.tsx
"use client";

import * as Sentry from "@sentry/nextjs";
import NextError from "next/error";
import { useEffect } from "react";

export default function GlobalError({
  error,
}: {
  error: Error & { digest?: string };
}) {
  useEffect(() => {
    Sentry.captureException(error);
  }, [error]);

  return (
    <html>
      <body>
        <NextError statusCode={0} />
      </body>
    </html>
  );
}

5. Build and source maps

withSentryConfig uploads source maps during the build. Since version 11 you import it from @sentry/nextjs/config. The sentryUrl option points it at Fehlo instead of sentry.io.

next.config.ts
import type { NextConfig } from "next";
import { withSentryConfig } from "@sentry/nextjs/config";

const nextConfig: NextConfig = {};

export default withSentryConfig(nextConfig, {
  sentryUrl: "https://app.fehlo.de/",
  org: "<organisation-slug>",
  project: "<project-slug>",
  authToken: process.env.SENTRY_AUTH_TOKEN,
  silent: !process.env.CI,
  widenClientFileUpload: true,
});

Create the token in Fehlo under Settings, API tokens, with the preset "For source maps". The organisation and project slugs are in the address bar of the project settings: /<organisation>/settings/projects/<project>. Set the token as SENTRY_AUTH_TOKEN in CI, not in code.

6. Test it

Add a page with a button that throws and open it in the browser:

app/fehlo-test/page.tsx
"use client";

export default function FehloTest() {
  return (
    <button type="button" onClick={() => { throw new Error("Fehlo test error"); }}>
      Test error
    </button>
  );
}

Measure performance

Add tracesSampleRate: 0.2, to all three Sentry.init calls. In Fehlo, transactions count against their own allowance, not against your events.

Questions

Nothing arrives. What should I check?

First the DSN: it has to point at app.fehlo.de. Second, whether your server or browser can reach https://app.fehlo.de (firewall, proxy, ad blocker). Third, whether this month's quota is used up; you get an email when it is. Fourth, whether sampleRate or beforeSend drops events. If only performance data is missing, this month's transactions may be used up.