DEV Community

DevHelm
DevHelm

Posted on • Originally published at devhelm.io

OpenTelemetry vs Jaeger: What Each One Does and How They Fit Together

"OpenTelemetry vs Jaeger" is one of the most searched comparisons in observability — and it's based on a misunderstanding. OpenTelemetry and Jaeger are not competitors. They operate at different layers of the tracing stack and are designed to work together.

OpenTelemetry is the instrumentation and collection layer. It provides the SDKs you use to generate spans in your code, the wire protocol (OTLP) that transports those spans, and the Collector that routes and processes them.

Jaeger is the storage and query layer. It receives spans, writes them to a database (Elasticsearch, Cassandra, or others), and provides a UI for searching and visualizing traces.

The standard production pipeline uses both: OTel SDK → OTel Collector → Jaeger.

Why people think they compete

The confusion comes from history. Before OpenTelemetry existed, Jaeger shipped its own client SDKs — jaeger-client-go, jaeger-client-java, jaeger-client-node, and others. These SDKs generated spans in Jaeger's native format and sent them directly to the Jaeger collector. If you used Jaeger, you used Jaeger's SDK.

OpenTelemetry replaced those SDKs. The Jaeger client libraries are deprecated as of 2022, and the Jaeger project officially recommends using OpenTelemetry SDKs for instrumentation. But the old tutorials, Stack Overflow answers, and blog posts that reference jaeger-client-* still rank in search results, creating the impression that you must choose one or the other.

You don't. Use OpenTelemetry for instrumentation; use Jaeger (or any other backend) for storage and visualization.

What OpenTelemetry provides

OpenTelemetry covers three concerns:

1. Instrumentation (SDKs)

The OTel SDKs generate spans from your application code. Auto-instrumentation libraries automatically create spans for common frameworks — HTTP servers, HTTP clients, database drivers, gRPC, message queues. You don't need to manually add spans for standard operations.

npm install @opentelemetry/sdk-node @opentelemetry/auto-instrumentations-node
Enter fullscreen mode Exit fullscreen mode

A few lines of setup code and every Express handler, every pg query, and every axios call produces a span with timing, attributes, and parent-child relationships.

2. Protocol (OTLP)

The OpenTelemetry Protocol defines a standard wire format for traces, metrics, and logs. Any OTel SDK can export to any OTLP-compatible backend. Any OTLP-compatible backend can receive data from any OTel SDK. This decouples your code from your backend choice.

3. Collection and routing (OTel Collector)

The Collector sits between your SDKs and your backends. It batches spans, samples them, enriches them with metadata, and exports to one or more destinations. You can send traces to Jaeger, metrics to Prometheus, and logs to Loki — all from one Collector instance.

What Jaeger provides

Jaeger covers the complementary concerns:

1. Span storage

Jaeger writes spans to a database — Elasticsearch, Cassandra, Kafka (as a buffer), or Badger (for small deployments). The storage layer handles indexing, retention policies, and query optimization.

2. Trace query API

A REST and gRPC API for finding traces by service name, operation, tags, duration range, and time window. This is the read path that your dashboards and UI depend on.

3. Visualization

The Jaeger UI renders the span tree as a timeline, shows service dependency graphs, and supports trace comparison — diffing two traces side by side to identify where they diverge.

4. Sampling decisions

Jaeger supports remote sampling — the collector tells the SDK what percentage of traces to record. Adaptive sampling adjusts rates per service based on traffic volume. These are decisions about which spans to keep, not about how to generate them.

The standard pipeline

Here's how they connect in a typical production deployment:

Your Application
  └── OTel SDK (auto-instrumentation)
        │ OTLP (gRPC or HTTP)
        ▼
  OTel Collector
  ├── batch processor
  ├── memory_limiter processor
  └── OTLP exporter
        │ OTLP (gRPC)
        ▼
  Jaeger Collector
  └── Elasticsearch / Cassandra
        │
        ▼
  Jaeger Query + UI
Enter fullscreen mode Exit fullscreen mode

Your application code only interacts with the OTel SDK. It never imports jaeger-client, never constructs Jaeger-specific spans, never speaks Jaeger's native wire format. If you switch from Jaeger to Grafana Tempo next quarter, you change the Collector's exporter config. Your application code stays the same.

When you'd use OTel without Jaeger

If you already run a different tracing backend, you still use OTel for instrumentation. The OTel Collector exports to:

  • Grafana Tempo — object-storage-based, cheapest at scale
  • Datadog APM — fully managed SaaS
  • Honeycomb — columnar storage, great for high-cardinality queries
  • Elastic APM — if you already run Elasticsearch
  • Zipkin — simpler alternative to Jaeger

In all cases, the instrumentation is identical. Only the Collector's exporter changes.

When you'd use Jaeger without OTel

This is the deprecated path. The Jaeger client SDKs (jaeger-client-*) still function but receive no new features and no bug fixes beyond critical security patches. If you have existing code instrumented with Jaeger clients, it works — but any new instrumentation should use OpenTelemetry SDKs.

The migration is straightforward: replace the Jaeger client SDK with the OTel SDK, configure the OTLP exporter to point at your existing Jaeger collector, and remove the Jaeger client dependency. Your Jaeger collector, storage, and UI remain unchanged.

The recommendation

Always start with OpenTelemetry for instrumentation. It's vendor-neutral, actively maintained, and supported by every major observability backend. You'll never regret the investment.

Pick Jaeger as your backend if you want open-source trace storage with a full-featured UI, adaptive sampling, and CNCF governance. See our Jaeger deep-dive and Jaeger vs Zipkin comparison for more on the backend choice.

Pick a different backend if your needs point elsewhere — Tempo for cost-efficiency at scale, Datadog for managed convenience, Honeycomb for high-cardinality queries.

The key insight is that the instrumentation decision and the backend decision are independent. Make them separately, and you'll have the flexibility to change either without affecting the other.

Monitor your tracing infrastructure — both the OTel Collector and your Jaeger backend — with external health checks at app.devhelm.io. A 30-second check on your Collector's health endpoint and Jaeger's query service catches failures before your trace data has gaps.


Originally published on DevHelm.

Top comments (0)