What is context propagation in OpenTelemetry?
Quick Answer
Context propagation is the mechanism that carries trace context (trace ID, span ID, and trace flags) across service boundaries so that spans from different services can be correlated into a single end-to-end trace. It works by injecting context into transport headers (like HTTP headers) on outgoing requests and extracting it on incoming requests.
Detailed Answer
Think of context propagation like a relay race baton. When the first runner (checkout-service) starts the race (trace), they carry a baton (trace context) with the race ID written on it. When they hand off to the second runner (order-processing-service), the baton transfers, and the second runner continues the same race. Without the baton handoff, each runner would think they are running a separate race, and you would never know they were part of the same event.
Context propagation is the foundation that makes distributed tracing work across service boundaries. When checkout-service receives a user request, the OpenTelemetry SDK generates a trace ID (a 128-bit identifier like 4bf92f3577b34da6a3ce929d0e0e4736) and creates a root span. When checkout-service makes an HTTP call to order-processing-service, the SDK's propagator injects the trace ID and current span ID into the outgoing HTTP headers. The most common format is W3C Trace Context, which uses two headers: traceparent (containing the trace ID, parent span ID, and trace flags) and tracestate (carrying vendor-specific data). When order-processing-service receives the request, its SDK extracts the trace context from the headers and creates a new span with the propagated trace ID and the incoming span ID as the parent.
OpenTelemetry supports multiple propagation formats through its propagator API. The W3C Trace Context format is the default and the recommended standard, defined in a W3C specification. The B3 format (used by Zipkin) is supported for backward compatibility with systems already using B3 headers. The Jaeger propagation format uses the uber-trace-id header. You can configure the SDK to use multiple propagators simultaneously, which is essential during migrations: if payments-api uses W3C format but a legacy inventory-sync still sends B3 headers, the Collector or SDK can understand both. The propagation format is typically set globally for all services in an organization to ensure consistency.
Context propagation is not limited to HTTP. OpenTelemetry propagates context through gRPC metadata, message queue headers (Kafka record headers, RabbitMQ message properties), and even custom transports. When order-processing-service publishes a message to a Kafka topic, the producer instrumentation injects the trace context into the Kafka record headers. When inventory-sync consumes that message, the consumer instrumentation extracts the context and creates a span linked to the original trace. This means the entire flow from user click through synchronous HTTP calls through asynchronous message processing appears as a single connected trace.
In production, broken context propagation is one of the most common reasons traces appear fragmented. If a proxy, API gateway, or load balancer strips custom headers, the trace context is lost and downstream services start new traces instead of continuing the existing one. Platform teams at companies running services like user-auth-service and checkout-service debug this by checking whether the traceparent header survives through every hop. Another common issue is mixing propagation formats: if checkout-service injects W3C headers but payments-api only extracts B3 format, the trace breaks at that boundary. Setting a consistent propagation format across all services and ensuring that infrastructure components (Nginx, Envoy, AWS ALB) forward trace headers are essential operational steps.