Next.js
Use autotel-adapters/next to wrap App Router Route Handlers with one helper.
It creates a span per request and exposes a request-scoped logger. Pair with
init() from autotel for the SDK setup.
Installation
Section titled “Installation”npm install autotel autotel-adaptersFor HTTP and database auto-instrumentation, also install:
npm install @opentelemetry/auto-instrumentations-node1. Initialise
Section titled “1. Initialise”Use Next.js's official instrumentation hook so init() runs before any
request is served:
// instrumentation.ts (project root)export async function register() { if (process.env.NEXT_RUNTIME === 'nodejs') { const { init } = await import('autotel'); init({ service: 'my-next-app', endpoint: process.env.OTEL_EXPORTER_OTLP_ENDPOINT, }); }}module.exports = { experimental: { instrumentationHook: true, // not required on Next 15+ },};Edge runtime: for
export const runtime = 'edge'routes, useautotel-edgeinstead.init()from the Node.js package won't run there.
2. Wrap Route Handlers
Section titled “2. Wrap Route Handlers”import { withAutotel, useLogger, parseError } from 'autotel-adapters/next';
export const POST = withAutotel(async (request: Request) => { const log = useLogger(request); log.set({ feature: 'checkout' });
try { const body = await request.json(); const result = await processCheckout(body); log.set({ orderId: result.id }); return Response.json(result); } catch (error) { const parsed = parseError(error); log.set({ error_status: parsed.status, error_why: parsed.why }); throw error; }});withAutotel creates the span and the request logger; useLogger(request)
returns the logger bound to the active request.
Patterns
Section titled “Patterns”Server components and server actions
Section titled “Server components and server actions”Use the functional trace() API directly. There's no request boundary to
wrap:
import { trace } from 'autotel';
const loadOrders = trace((ctx) => async (userId: string) => { ctx.setAttribute('user.id', userId); return db.orders.findMany({ where: { userId } });});
export default async function Page() { const orders = await loadOrders('123'); return <OrdersTable orders={orders} />;}// app/actions.ts ("use server")'use server';import { trace } from 'autotel';
export const createOrder = trace((ctx) => async (data: OrderData) => { ctx.setAttribute('source', 'server-action'); return db.orders.create({ data });});Structured errors → toasts
Section titled “Structured errors → toasts”Throw on the server with createStructuredError, parse on the client with
parseError for a richer error UI:
// serverimport { createStructuredError } from 'autotel';
if (!user) { throw createStructuredError({ message: 'User not found', status: 404, why: `No user with ID "${userId}"`, fix: 'Check the URL and try again', });}// clientimport { parseError } from 'autotel';
try { await fetch('/api/checkout', { method: 'POST', body });} catch (err) { const error = parseError(err); toast.error(error.message, { description: error.why });}Auto-instrumentation
Section titled “Auto-instrumentation”For automatic tracing of fetch, pg, mongodb, and other libraries on the
Node runtime, see
Auto-Instrumentation.
When to use what
Section titled “When to use what”Use withAutotel() for Route Handlers and Pages Router API routes
(pages/api/*). Use useLogger() on its own in server components or actions
where a span already exists higher up the call stack; wrapping with
withAutotel() again would duplicate the span. For domain functions and
server actions outside an HTTP boundary, use trace() from autotel
directly.
Examples
Section titled “Examples”example-nextjs— Next.js withautotel-adapters/nextandparseError()for client-side error handling.
Related
Section titled “Related”- Adapters — full
autotel-adaptersreference. - Auto-Instrumentation — HTTP, databases, etc.
- Edge Runtimes — for
runtime = 'edge'routes.