Next.js

A Next.js setup has two routes: a catch-all route handler for the API, and a page for the dashboard.

The API

Create app/api/breadcrumb/[...path]/route.ts, matching the basePath you passed to breadcrumb():

import { toNextHandler } from "@breadcrumb-sh/core/next";
import { bc } from "@/lib/breadcrumb";

export const { GET, POST, DELETE } = toNextHandler(bc);

toNextHandler returns one function per method; export the ones you need. DELETE is what revoking an MCP key uses.

The dashboard

Create app/admin/traces/[[...slug]]/page.tsx:

import { BreadcrumbDashboard } from "@breadcrumb-sh/react";

export default function TracesPage() {
  return (
    <div style={{ height: "100dvh" }}>
      <BreadcrumbDashboard api="/api/breadcrumb" basePath="/admin/traces" />
    </div>
  );
}

Then import the stylesheet once in app/layout.tsx:

import "@breadcrumb-sh/react/styles.css";

Two routes rather than one because the App Router will not put a route.ts and a page.tsx on the same segment. The optional catch-all is what gives each trace a shareable URL. See Dashboard for props, custom pages, and server rendering deep links.

TIP

On serverless (including Vercel), flush spans before the function returns so none are lost when the runtime freezes. See Production.

If you use better-sqlite3 in development, add it to serverExternalPackages in next.config.ts so Next leaves the native module alone:

export default { serverExternalPackages: ["better-sqlite3"] };

Next steps