Back to docs

Next.js App Router

Capture and replay your first Next.js backend run in 5 minutes.

Three steps: install, add env vars, wrap your route. No CLI, no generators, no config files beyond next.config.ts.

1

Install and configure env vars

Create an app in FluxRun, then add these server-only values to local development and your deployment environment.

shell
npm install fluxrun
.env
FLUX_PROJECT_TOKEN=fbproj_...
FLUX_PUBLIC_KEY=fluxpub_v1_...
FLUX_PRIVATE_KEY=fluxpriv_v1_...

Tip: You only need these three values. The SDK already knows the production ingest endpoint, so no URL configuration is required.

2

Wrap Next config

This snippet should typecheck on Next 15 without casts.

typescript
// next.config.ts
import type { NextConfig } from 'next';
import { withFluxNextJsPlugin } from 'fluxrun/build';

const nextConfig: NextConfig = {};

const withFlux = withFluxNextJsPlugin();
export default withFlux(nextConfig);

Why: The plugin rewrites host-module imports so Next can bundle them correctly before the route compiles.

3

Wrap one route handler

Use fluxHost for live SDK clients or database handles. The host method can keep normal typed parameters.

typescript
// app/api/orders/route.ts
import { withFluxNextJs } from 'fluxrun/adapters/next';
import { fluxHost } from 'fluxrun';
import { prisma } from '@/lib/prisma';

export const runtime = 'nodejs';

type OrderInput = { amount: number; currency: string };

const db = fluxHost('db', {
  createOrder: async (input: OrderInput) => prisma.order.create({ data: input }),
});

export const POST = withFluxNextJs(
  'orders.create',
  async (flux) => {
    const body = flux.request.body as OrderInput;
    const order = await db.createOrder(body);
    return { status: 201, body: { id: order.id } };
  },
  { host: { db } },
);

Required: Always export runtime = "nodejs" in traced routes. FluxRun uses QuickJS, which needs the Node.js runtime. Without this, the route will fail at runtime.

Why fluxHost: Prisma and other live clients cannot be serialized into the QuickJS sandbox. fluxHost keeps them on the host side while recording every call for replay.

4

Add the replay agent route

Save this deployed URL in the app dashboard, for example https://your-app.com/api/flux-agent.

typescript
// app/api/flux-agent/route.ts
import { fluxAgent } from 'fluxrun';

export const runtime = 'nodejs';

const corsHeaders = {
  'Access-Control-Allow-Origin': 'https://app.fluxrun.dev',
  'Access-Control-Allow-Headers': 'Content-Type, Authorization',
  'Access-Control-Allow-Methods': 'POST, OPTIONS',
};

export async function OPTIONS() {
  return new Response(null, { headers: corsHeaders });
}

export async function POST(req: Request) {
  const result = await fluxAgent(await req.json(), {
    authorization: req.headers.get('authorization'),
  });
  return Response.json(result, { headers: corsHeaders });
}

Why: The dashboard never holds your private key. When you click "replay," the dashboard asks your agent to decrypt and re-run the trace using your key.

5

Optional local ingest stub

Normal apps should not set FLUX_INGEST_URL in production. For local smoke tests only.

typescript
// app/api/flux-ingest/v1/executions/route.ts
type LocalFluxBatch = {
  executionId?: string;
  summary?: { executionId?: string };
  events?: unknown[];
};

export const runtime = 'nodejs';

export async function POST(req: Request) {
  const batch = (await req.json()) as LocalFluxBatch;
  console.log('[fluxrun local ingest]', {
    executionId: batch.executionId ?? batch.summary?.executionId,
    events: batch.events?.length ?? 0,
  });
  return Response.json({ ok: true });
}

Tip: Skip this step if you are deploying straight to production. The SDK sends traces to FluxRun automatically.

Verify it works

Build the app, trigger the route, then open the dashboard. A successful setup shows a new execution with request, host calls, fetches, console, errors, and replay actions.

shell
npm install fluxrun
npm run build
curl -X POST http://localhost:3000/api/orders \
  -H 'content-type: application/json' \
  -d '{"amount":1250,"currency":"usd"}'
Expect: 200 OK + execution appears in dashboard

Common Next.js pitfalls

Use Node.js runtime

Traced App Router handlers and the agent route should export runtime = "nodejs".

Do not set FLUX_INGEST_URL in production

The SDK already knows the production ingest endpoint. Set it only for local or private ingest overrides.

Local ingest path is appended

If FLUX_INGEST_URL=/api/flux-ingest, FluxRun posts to /api/flux-ingest/v1/executions.

Keep private keys server-side

FLUX_PRIVATE_KEY belongs only in server runtimes that run traced routes and the agent route.

Wrap host boundaries

Put Prisma, Redis, queues, payment clients, and other live SDK clients behind fluxHost.

Verify the agent URL

Save the deployed /api/flux-agent URL in the dashboard before decrypt or replay.