Skip to content
Docs menu
Integration · Next.js

Next.js

Three small server wrappers and one React provider cover every error a Next.js app can throw. withNreactive wraps App Router route handlers, withNreactiveAction wraps server actions, withNreactivePagesApi wraps Pages Router API handlers, and <NreactiveProvider> catches everything in the browser — runtime exceptions, unhandled rejections, fetch and XHR failures, console errors, resource load failures, CSP violations, long tasks, and React render-time errors that never reach window.onerror. Works with Next 14, 15, 16 on Node ≥ 20.

AI-assisted setup

Paste the prompt below into Claude Code, Cursor, Copilot, or Codex — your agent will detect your package manager, install both packages, set up instrumentation.ts, wrap each route handler and server action, and mount the provider in your root layout.

AI agent prompt · Next.js
You are adding the @nreactive/core + @nreactive/next SDKs to this Next.js project. nreactive is a production error-monitoring service that opens AI-generated pull requests to fix the errors it catches.

Do the following with the project's existing package manager (detect it from the lockfile: package-lock.json → npm, pnpm-lock.yaml → pnpm, yarn.lock → yarn, bun.lockb → bun):

1. Install the packages @nreactive/core and @nreactive/next.
2. Create or update "instrumentation.ts" at the project root (or "src/instrumentation.ts" if the project uses a "src/" layout) so that the "register" function calls init from @nreactive/core when NEXT_RUNTIME is "nodejs":

   export async function register() {
     if (process.env.NEXT_RUNTIME !== "nodejs") return;
     const { init } = await import("@nreactive/core");
     init({
       appId: process.env.NREACTIVE_APP_ID!,
       environment: process.env.NODE_ENV,
       release: process.env.APP_VERSION,
     });
   }

3. In every App Router route handler under app/api/**, wrap the exported HTTP handlers with withNreactive from @nreactive/next:

   import { withNreactive } from "@nreactive/next";
   export const GET = withNreactive(async (req) => Response.json({ ok: true }));

4. In every server action ("use server") that throws on user input, wrap the action with withNreactiveAction from @nreactive/next so the server-action context is attached to captured errors.

5. In every Pages Router API handler under pages/api/**, wrap the default export with withNreactivePagesApi from @nreactive/next.

6. In the root app/layout.tsx (or pages/_app.tsx for Pages Router), wrap {children} with <NreactiveProvider appId={process.env.NEXT_PUBLIC_NREACTIVE_APP_ID!}> imported from "@nreactive/next/client". The provider is a strict superset of the standalone browser script — it intercepts runtime exceptions, unhandled rejections, fetch and XHR failures, console.error/warn, resource load errors, CSP violations, and long tasks, AND it adds a React Error Boundary that catches render-time errors.

   IMPORTANT: if the project already includes <script src="https://nreactive.com/integration.js"> anywhere, REMOVE it. Running both would double-fire events.

7. Add NREACTIVE_APP_ID= and NEXT_PUBLIC_NREACTIVE_APP_ID= to .env.example (create it if missing). Both should hold the same value — the public one is the only environment variable visible to the client provider. The user obtains their App ID from https://nreactive.com/dashboard/apps.

8. Restart the dev server and trigger a test error from a route handler (throw new Error("nreactive test")) and from a client component (throw inside a useEffect or a button onClick) to confirm both server and client events appear in the dashboard.

Do not invent additional configuration. If the project uses Edge Runtime for some routes, leave those routes unwrapped — withNreactive depends on Node's async_hooks. Stop and ask if the project structure doesn't match these assumptions.

Manual setup

1

Get your App ID

Sign in and grab your App ID from the Apps page. It looks like app_ab12cd34ef. Export it as both NREACTIVE_APP_ID (server) and NEXT_PUBLIC_NREACTIVE_APP_ID (client) — the public copy is the only env var Next.js exposes to the browser provider.

2

Install

pnpm add @nreactive/core @nreactive/next

Or npm install @nreactive/core @nreactive/next / yarn add … / bun add ….

3

Wire it up

Create instrumentation.ts at the project root (or src/instrumentation.ts if you use a src/ layout). Next.js calls register() once per worker:

export async function register() {
  if (process.env.NEXT_RUNTIME !== "nodejs") return;
  const { init } = await import("@nreactive/core");
  init({
    appId: process.env.NREACTIVE_APP_ID!,
    environment: process.env.NODE_ENV,
    release: process.env.APP_VERSION,
  });
}

Wrap each App Router route handler:

// app/api/users/route.ts
import { withNreactive } from "@nreactive/next";
 
export const GET = withNreactive(async (request) => {
  return Response.json({ users: [] });
});
 
export const POST = withNreactive(async (request) => {
  const body = await request.json();
  return Response.json({ ok: true });
});

Wrap each server action:

// app/actions.ts
"use server";
import { withNreactiveAction } from "@nreactive/next";
 
export const submitContact = withNreactiveAction(async (formData: FormData) => {
  // throws here are captured with kind: "server-action"
});

Wrap each Pages Router API handler (if you still use Pages Router):

// pages/api/users.ts
import { withNreactivePagesApi } from "@nreactive/next";
 
export default withNreactivePagesApi(async (req, res) => {
  res.json({ users: [] });
});

Mount the provider in your root layout. The "use client"; directive is already baked into the bundle so you can import it from a server component:

// app/layout.tsx
import { NreactiveProvider } from "@nreactive/next/client";
 
export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>
        <NreactiveProvider appId={process.env.NEXT_PUBLIC_NREACTIVE_APP_ID!}>
          {children}
        </NreactiveProvider>
      </body>
    </html>
  );
}

If you previously used <script src="https://nreactive.com/integration.js"> remove it now — the provider is a strict superset of that script and running both would double-fire events.

4

Verify

Throw a server error from a route handler:

// app/api/boom/route.ts
import { withNreactive } from "@nreactive/next";
 
export const GET = withNreactive(async () => {
  throw new Error("nreactive server test");
});
curl http://localhost:3000/api/boom

Throw a React render error from a client component:

"use client";
import { useEffect } from "react";
 
export function BoomButton() {
  return (
    <button onClick={() => { throw new Error("nreactive client test"); }}>
      Crash me
    </button>
  );
}

Within a few seconds both events show up on the Errors page of your dashboard — the server one with method, URL, request ID, and headers; the client one with errorType: ReactRenderError and the component stack.

Next steps