@stacknext/next provides three
optional helpers for adding application evidence to the same request trace:
registerStackNext(); they do not create a second SDK, exporter or collector
connection. If StackNext is inert (no token or collector URL), the helpers are
effectively no-ops through the OpenTelemetry no-op provider.
Signatures
Options
What the helpers guarantee
- Same trace. The span is started with
startActiveSpan, so it becomes the active OpenTelemetry context. Nested StackNext or OpenTelemetry spans parent correctly. Outside any request context, a helper starts a new trace root. - Return values are preserved. The callbacks may return a value, a promise or nothing. The helpers return or resolve with the same result.
- Errors are preserved. The original error is recorded on the span and
rethrown unchanged. Callers can still use
try/catch. - Control flow is preserved. App Router
redirect(),notFound()and HTTP fallback errors use thrown digest objects. The helpers rethrow them without marking the span as failed. - Concurrency is isolated. The active span comes from OpenTelemetry context, not a module-level variable. Concurrent requests and concurrent calls within one request do not cross-parent.
- Attributes are sanitized centrally. The exporter applies the same sanitizer used for Next.js spans before the collector’s second redaction pass.
- No blocking network I/O. Span creation and ending are local. The existing bounded transport batches export in the background.
- Explicit markers. Helpers add
stacknext.manual: trueandstacknext.span.kind("custom"or"action"). Coverage and the trace explorer use these markers.
Examples
Measure a route handler
Measure a synchronous library call
Measure a database driver
Measure a Server Component
Server Actions
Next.js callsonRequestError for failures, not for successful actions. A
successful action that updates a row, revalidates a page and returns a value
does not produce an error event, so it would be invisible if StackNext relied
only on the error hook. The documented Next.js telemetry does not expose a
stable per-action name that StackNext can use without patching internals.
withStackNextAction() creates an explicit span with the same active trace as
the request, a stable name you choose, stacknext.manual: true and
stacknext.span.kind: "action". The trace explorer classifies it as
app/custom, and coverage reports it under custom.server-actions.
Basic usage
FormData object, field values, cookies, headers, file contents
or raw request bodies as attributes.
Failures
Thrown errors are recorded on the action span and rethrown unchanged:onRequestError, producing a correlated error entry.
Check the trace to see the action span, the error and any failed query together.
Redirects, notFound() and revalidation
redirect(), notFound() and HTTP fallbacks work by throwing special
control-flow objects. They are normal outcomes: the helper rethrows them and
does not mark the span as an error. Keep the redirect inside the callback so the
action span covers that path.
revalidatePath() and revalidateTag() are ordinary calls. Put them inside the
action callback so their work stays within the action span. Revalidation itself
is not a separate StackNext span.
Concurrency
Each call uses OpenTelemetry’s active context, so concurrent actions do not share a parent accidentally:What is not automatic
- No automatic action naming. Only exported actions you wrap have a named action span.
- No argument or form capture. Argument values,
FormDataentries, files and return values are not recorded automatically. - No browser/client tracing. The span records server-side execution.
- No Edge support. The helper is part of the Node.js runtime integration.
- No guarantee that every failure is correlated. Failures normally reach
onRequestError; an error outside Next.js’s error path may be missing or rely on route/time fallback correlation.
Attributes and privacy
The helpers accept arbitrary attribute-shaped data, but not every value is retained. The sanitizer:- replaces header/cookie/authorization/password/token/secret-shaped keys;
- removes query strings and fragments from URL-like strings;
- passes strings through text redaction and length caps;
- drops nested objects and unsupported types rather than serializing them blindly.
Operation boundaries
- Do not wrap an entire request. Next.js already creates the request root. Wrapping everything creates an overlapping parent and makes the timeline harder to read.
- Do not sum overlapping spans. A parent span already contains its children. Use the waterfall to compare work.
- Keep names stable and low-cardinality. Use
catalog.refresh, notcatalog.refresh?sku=...or a user id. - Use
withStackNextSpanSynconly for synchronous work. An async callback returns a promise without awaiting it, so the span can end too early.
Coverage and the trace explorer
Custom spans appear in the request/trace waterfall as app/custom spans. Coverage reportscustom.spans as observed when at least one marked custom
span is in the sample, and custom.server-actions when action spans are present.
The two markers are separate: a generic custom span does not claim to be a
Server Action.
Manual spans are optional. custom.spans: unknown only means the sample
contains no marked custom spans; it does not mean the application is
uninstrumented or unhealthy.