Skip to content

ADR-0004 — @vercel/otel pinned to 1.x on Next.js

Status: Accepted Date: 2026-04-16 Author(s): Platform engineering

Context

Browser and SSR traces from ebit-fe need to reach the OTel Collector alongside the NestJS backend spans. @vercel/otel provides the registerOTel() helper that wires the Node.js OTel SDK inside Next.js's instrumentation.ts hook, including automatic fetch span creation and traceparent injection on outbound requests.

At the time of integration, OpenTelemetry JS had two major release lines: 1.x (@opentelemetry/sdk-trace-web@^1.30, exporters/instrumentations at ^0.57) and the emerging 2.x line. @vercel/otel@1.13.0 declares peer dependencies on the 1.x line. Installing any 2.x OTel package alongside it causes peer-dep warnings at install time and, worse, silent SSR trace shadowing at runtime — two competing TracerProvider registrations fight over the global, and the loser's spans are dropped without error.

A second complication: Sentry v9 (@sentry/nextjs@^9.11.0) is also OTel-based. Sentry.init() grabs the global tracer provider on import, even when the DSN is empty. If the Sentry server config is imported before registerOTel(), Sentry's provider wins and @vercel/otel spans are silently lost.

Decision

  1. Pin all OTel browser and SSR packages to the 1.x/0.57.x line. ebit-fe/package.json locks @vercel/otel at 1.13.0, @opentelemetry/api at 1.9.0, @opentelemetry/sdk-trace-web at ^1.30.1, and all instrumentations/exporters at ^0.57.2. No 2.x packages are permitted until @vercel/otel officially supports them.

  2. Gate the Sentry import on NEXT_PUBLIC_SENTRY_DSN. In ebit-fe/src/instrumentation.ts:7-12, the await import('../sentry.server.config') is only executed when a DSN is configured. Otherwise, registerOTel() runs and owns the global provider. This prevents the silent provider conflict in local dev and compose environments where Sentry is not needed.

  3. Require propagateContextUrls: [/.*/] in registerOTel. At ebit-fe/src/instrumentation.ts:18-22, the fetch instrumentation config injects traceparent on all outbound requests, not just same-origin. Without this, cross-service ebit-fe → ebit-api spans orphan in Jaeger.

Alternatives considered

  1. Upgrade to OTel JS 2.x. Rejected: @vercel/otel@1.x is the current stable release compatible with Next.js 14. A 2.x upgrade requires waiting for Vercel to publish a compatible version. Mixing 1.x and 2.x providers produces silent data loss.

  2. Drop @vercel/otel and wire the OTel SDK manually. Rejected: registerOTel handles the Next.js instrumentation.ts lifecycle correctly (server-only registration, proper shutdown hooks, fetch monkey-patching that respects Next.js's patched fetch). Reimplementing this is fragile and couples us to Next.js internals.

  3. Use Sentry as the sole trace provider (no @vercel/otel). Rejected: in local dev and compose, there is no Sentry DSN. Traces would only exist in production. The two-provider gate gives us OTel traces in every environment — Sentry in prod (when DSN is set), @vercel/otel → Collector locally.

  4. Allow floating version ranges (^1.13.0). Rejected for @vercel/otel specifically: a minor bump could pull in a transitive 2.x dep. Exact pinning prevents surprise breakage on pnpm install.

Consequences

  • pnpm add @opentelemetry/anything in ebit-fe must be verified against the 1.x peer matrix before merging. A CI check or Renovate grouping rule would prevent accidental 2.x introduction.
  • The Sentry gate means local dev never sends error events to Sentry. This is acceptable — Sentry is a production concern; local errors surface in console/Jaeger.
  • If Vercel ships @vercel/otel@2.x, all OTel deps in ebit-fe/package.json must be upgraded as a single atomic PR. The pinning strategy makes this a deliberate migration, not an accidental drift.

References

  • ebit-fe/src/instrumentation.ts:7-24 — Sentry gate + registerOTel with propagateContextUrls
  • ebit-fe/package.json:18-26 — OTel 1.x dependency versions
  • ebit-fe/package.json:42@sentry/nextjs@^9.11.0
  • ebit-fe/package.json:47@vercel/otel@1.13.0