Blog/Tech News & Opinions/OpenTelemetry Is Becoming the Observability Standard
POST
January 05, 2026
LAST UPDATEDJanuary 05, 2026

OpenTelemetry Is Becoming the Observability Standard

Learn why OpenTelemetry is becoming the standard for distributed tracing, metrics, and logging, and how to instrument your Node.js and Next.js apps.

Tags

OpenTelemetryObservabilityDevOpsMonitoring
OpenTelemetry Is Becoming the Observability Standard
5 min read

OpenTelemetry Is Becoming the Observability Standard

TL;DR

OpenTelemetry (OTel) provides a vendor-neutral standard for collecting traces, metrics, and logs from your applications. Instrument your code once with OTel, and export to any observability backend --- Datadog, Grafana, Honeycomb, Jaeger --- without changing application code. It is becoming the observability equivalent of what SQL is for databases.

What's Happening

The observability landscape used to require choosing a vendor early and instrumenting your code with their proprietary SDK. Switch from Datadog to Grafana Cloud? Rewrite your instrumentation. Want to try Honeycomb alongside New Relic? Run two SDKs with overlapping overhead.

OpenTelemetry, a CNCF (Cloud Native Computing Foundation) project, has changed this by providing a single instrumentation standard that works with any backend. It has reached stable status for traces and metrics, with logs nearing general availability. Major observability vendors --- Datadog, Grafana, Splunk, Honeycomb, New Relic, Dynatrace --- all support OTel ingestion natively.

The shift is practical, not ideological. Teams adopt OTel because it reduces vendor lock-in, simplifies instrumentation, and provides a unified data model across languages. Next.js has built-in OTel support. Node.js has mature auto-instrumentation packages. The barrier to entry has dropped significantly.

Why It Matters

Observability is not optional for production applications. When a request is slow, an error rate spikes, or a deployment causes regressions, you need traces, metrics, and logs to diagnose the issue. The question is how you collect that telemetry.

Vendor-specific SDKs create lock-in. Once you have instrumented thousands of lines of code with Datadog's dd-trace, switching to another vendor is a significant engineering project. OTel eliminates this by decoupling instrumentation (how you collect data) from export (where you send it).

For Node.js and Next.js developers specifically, OTel means you can add production-grade observability with minimal effort and switch backends as your needs evolve.

How It Works / What's Changed

The Three Signals

OpenTelemetry collects three types of telemetry data:

Traces track a request's journey through your system, from the initial HTTP request through database queries, external API calls, and back to the response. Each operation is a "span" within the trace.

Metrics are numerical measurements over time: request count, response latency percentiles, error rates, queue depths, CPU usage.

Logs are timestamped event records. OTel correlates logs with traces so you can see exactly which log entries belong to which request.

Setting Up OTel in Node.js

The setup involves installing the SDK, configuring auto-instrumentation, and pointing the exporter to your backend:

bash
npm install @opentelemetry/sdk-node \
  @opentelemetry/auto-instrumentations-node \
  @opentelemetry/exporter-trace-otlp-http \
  @opentelemetry/exporter-metrics-otlp-http
typescript
// instrumentation.ts
import { NodeSDK } from '@opentelemetry/sdk-node';
import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';
import { OTLPMetricExporter } from '@opentelemetry/exporter-metrics-otlp-http';
import { PeriodicExportingMetricReader } from '@opentelemetry/sdk-metrics';
import { Resource } from '@opentelemetry/resources';
import {
  ATTR_SERVICE_NAME,
  ATTR_SERVICE_VERSION,
} from '@opentelemetry/semantic-conventions';
 
const sdk = new NodeSDK({
  resource: new Resource({
    [ATTR_SERVICE_NAME]: 'my-api',
    [ATTR_SERVICE_VERSION]: '1.0.0',
  }),
  traceExporter: new OTLPTraceExporter({
    url: process.env.OTEL_EXPORTER_OTLP_ENDPOINT + '/v1/traces',
  }),
  metricReader: new PeriodicExportingMetricReader({
    exporter: new OTLPMetricExporter({
      url: process.env.OTEL_EXPORTER_OTLP_ENDPOINT + '/v1/metrics',
    }),
    exportIntervalMillis: 30000,
  }),
  instrumentations: [
    getNodeAutoInstrumentations({
      '@opentelemetry/instrumentation-http': { enabled: true },
      '@opentelemetry/instrumentation-express': { enabled: true },
      '@opentelemetry/instrumentation-pg': { enabled: true },
      '@opentelemetry/instrumentation-redis': { enabled: true },
    }),
  ],
});
 
sdk.start();

The getNodeAutoInstrumentations function automatically instruments HTTP requests, database queries, Redis calls, and other common operations without modifying your application code.

OTel in Next.js

Next.js has native OpenTelemetry support through the instrumentation.ts file at the project root:

typescript
// instrumentation.ts (Next.js project root)
export async function register() {
  if (process.env.NEXT_RUNTIME === 'nodejs') {
    const { NodeSDK } = await import('@opentelemetry/sdk-node');
    const { OTLPTraceExporter } = await import(
      '@opentelemetry/exporter-trace-otlp-http'
    );
    const { getNodeAutoInstrumentations } = await import(
      '@opentelemetry/auto-instrumentations-node'
    );
 
    const sdk = new NodeSDK({
      traceExporter: new OTLPTraceExporter(),
      instrumentations: [getNodeAutoInstrumentations()],
    });
 
    sdk.start();
  }
}

Next.js also enables the experimental.instrumentationHook in next.config.js:

javascript
// next.config.js
module.exports = {
  experimental: {
    instrumentationHook: true,
  },
};

With this configuration, Next.js automatically creates spans for:

  • Server-side rendering
  • API route execution
  • Middleware processing
  • fetch calls made from Server Components
  • Static page generation

Custom Spans and Attributes

Auto-instrumentation captures the framework-level operations, but you often need custom spans for business logic:

typescript
import { trace, SpanStatusCode } from '@opentelemetry/api';
 
const tracer = trace.getTracer('my-api');
 
export async function processOrder(orderId: string) {
  return tracer.startActiveSpan('processOrder', async (span) => {
    try {
      span.setAttribute('order.id', orderId);
 
      // Validate the order
      const order = await tracer.startActiveSpan('validateOrder', async (validationSpan) => {
        const result = await db.query.orders.findFirst({
          where: eq(orders.id, orderId),
        });
        validationSpan.setAttribute('order.status', result?.status ?? 'not_found');
        validationSpan.end();
        return result;
      });
 
      if (!order) {
        span.setStatus({ code: SpanStatusCode.ERROR, message: 'Order not found' });
        throw new Error('Order not found');
      }
 
      // Charge payment
      await tracer.startActiveSpan('chargePayment', async (paymentSpan) => {
        paymentSpan.setAttribute('payment.amount', order.total);
        paymentSpan.setAttribute('payment.currency', 'USD');
        await paymentService.charge(order.paymentMethodId, order.total);
        paymentSpan.end();
      });
 
      span.setStatus({ code: SpanStatusCode.OK });
      return order;
    } catch (error) {
      span.setStatus({ code: SpanStatusCode.ERROR, message: String(error) });
      span.recordException(error as Error);
      throw error;
    } finally {
      span.end();
    }
  });
}

This creates a trace showing processOrder as the parent span with validateOrder and chargePayment as child spans, each with relevant attributes.

Custom Metrics

Beyond traces, you can record custom metrics for business and performance monitoring:

typescript
import { metrics } from '@opentelemetry/api';
 
const meter = metrics.getMeter('my-api');
 
// Counters for event counting
const orderCounter = meter.createCounter('orders.processed', {
  description: 'Number of orders processed',
});
 
// Histograms for measuring distributions
const orderValueHistogram = meter.createHistogram('orders.value', {
  description: 'Order value distribution in USD',
  unit: 'USD',
});
 
// Up-down counters for gauges
const activeConnections = meter.createUpDownCounter('db.connections.active', {
  description: 'Number of active database connections',
});
 
export async function handleOrder(order: Order) {
  orderCounter.add(1, { 'order.type': order.type });
  orderValueHistogram.record(order.total, { 'order.currency': 'USD' });
  // ...
}

Backend Compatibility

The same instrumentation code works with any OTel-compatible backend. You only change the exporter configuration:

typescript
// For Jaeger (self-hosted)
const exporter = new OTLPTraceExporter({
  url: 'http://jaeger:4318/v1/traces',
});
 
// For Grafana Cloud
const exporter = new OTLPTraceExporter({
  url: 'https://otlp-gateway-prod-us-central-0.grafana.net/otlp/v1/traces',
  headers: {
    Authorization: `Basic ${btoa(`${instanceId}:${apiKey}`)}`,
  },
});
 
// For Datadog
const exporter = new OTLPTraceExporter({
  url: 'http://datadog-agent:4318/v1/traces',
});
 
// For Honeycomb
const exporter = new OTLPTraceExporter({
  url: 'https://api.honeycomb.io/v1/traces',
  headers: {
    'x-honeycomb-team': process.env.HONEYCOMB_API_KEY!,
  },
});

This is the core value of OTel: your instrumentation code stays the same regardless of which backend you use. Switching from Jaeger to Grafana Cloud is a configuration change, not a code change.

The OTel Collector

For production deployments, the OTel Collector acts as a proxy between your application and your observability backend:

yaml
# otel-collector-config.yaml
receivers:
  otlp:
    protocols:
      grpc:
        endpoint: 0.0.0.0:4317
      http:
        endpoint: 0.0.0.0:4318
 
processors:
  batch:
    timeout: 5s
    send_batch_size: 1000
  memory_limiter:
    check_interval: 1s
    limit_mib: 512
 
exporters:
  otlp/grafana:
    endpoint: https://otlp-gateway.grafana.net/otlp
    headers:
      Authorization: "Basic ${GRAFANA_TOKEN}"
  otlp/jaeger:
    endpoint: jaeger:4317
    tls:
      insecure: true
 
service:
  pipelines:
    traces:
      receivers: [otlp]
      processors: [memory_limiter, batch]
      exporters: [otlp/grafana, otlp/jaeger]
    metrics:
      receivers: [otlp]
      processors: [memory_limiter, batch]
      exporters: [otlp/grafana]

The Collector lets you send telemetry to multiple backends simultaneously, apply sampling and filtering, batch data for efficiency, and keep sensitive credentials out of application code.

My Take

OTel is one of those technologies that pays for itself the first time you need to debug a production issue. Before I adopted it, debugging a slow API endpoint meant checking logs, guessing where the bottleneck was, and adding ad-hoc timing code. With OTel traces, I can see the exact breakdown: 200ms in the database, 150ms waiting for a third-party API, 50ms in serialization.

The auto-instrumentation is genuinely impressive. Installing the Node.js auto-instrumentation package and pointing it at a backend gives you useful traces with zero application code changes. Custom spans are worth adding for business-critical paths, but the automatic instrumentation covers the majority of what you need.

My one complaint is the SDK's API surface area. The OTel JavaScript SDK has many packages, configurations, and concepts. The getting-started experience could be simpler. But once you have a working configuration, it is largely set-and-forget.

What This Means for You

If you have no observability: Start with OTel and a free backend like Jaeger (self-hosted) or Grafana Cloud's free tier. Auto-instrumentation gets you useful traces immediately.

If you are using a vendor SDK: Plan a migration to OTel. Most vendors now support OTel ingestion, so you can switch incrementally without changing your backend.

If you are building a Next.js application: Enable the instrumentation hook and set up the OTel SDK. The built-in integration makes Next.js one of the easiest frameworks to instrument.

If you are choosing an observability backend: Choose based on features, pricing, and UI --- not on SDK compatibility. OTel makes the backend a swappable layer, so you can change your mind later without re-instrumenting.

FAQ

What is OpenTelemetry?

OpenTelemetry is a CNCF project providing vendor-neutral APIs, SDKs, and tools for collecting distributed traces, metrics, and logs from applications.

Why should I use OpenTelemetry instead of vendor SDKs?

OpenTelemetry lets you instrument once and export to any backend like Datadog, Grafana, or Honeycomb, avoiding vendor lock-in and reducing instrumentation effort.

Does Next.js support OpenTelemetry natively?

Yes, Next.js has built-in OpenTelemetry support via the instrumentation.ts file, automatically tracing server-side rendering, API routes, and middleware.

Collaboration

Need help with a project?

Let's Build It

I help startups and established companies design, build, and scale world-class digital products. From deep technical architecture to pixel-perfect UI — let's bring your vision to life.

SH

Article Author

Sadam Hussain

Senior Full Stack Developer

Senior Full Stack Developer with over 7 years of experience building React, Next.js, Node.js, TypeScript, and AI-powered web platforms.

Related Articles

Turbopack Is Replacing Webpack: What You Need to Know
Feb 08, 20267 min read
Turbopack
Webpack
Bundler

Turbopack Is Replacing Webpack: What You Need to Know

Understand why Turbopack is replacing Webpack as the default bundler in Next.js, with benchmarks showing 10x faster builds and what it means for you.

pnpm vs Yarn vs npm: Package Managers in 2026
Jan 22, 20266 min read
pnpm
Yarn
npm

pnpm vs Yarn vs npm: Package Managers in 2026

Compare pnpm, Yarn, and npm in 2026 across speed, disk usage, monorepo support, and security to choose the right package manager for your team.

Multi-Agent AI Systems: What Developers Should Know
Dec 01, 20255 min read
AI
Multi-Agent
LLM

Multi-Agent AI Systems: What Developers Should Know

Understand multi-agent AI architectures where specialized LLM agents collaborate on complex tasks, with patterns for orchestration, memory, and tooling.