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.
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
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.
Install
pnpm add @nreactive/core @nreactive/nextOr npm install @nreactive/core @nreactive/next / yarn add … / bun add ….
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.
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/boomThrow 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.