Skip to main content

Overview

Baggage is a mechanism for propagating name-value pairs across service boundaries. It allows you to attach custom attributes to telemetry context that can be accessed by any service in the call chain.
Baggage is not automatically added to spans, metrics, or logs. You must explicitly read baggage entries and add them to your telemetry.

What is baggage?

Baggage is a set of key-value pairs that:
  • Travels with the context across process boundaries
  • Can be read and modified by any service
  • Follows the W3C Baggage specification
  • Has size and count limits for safety

Limits

const MAX_KEY_VALUE_PAIRS: usize = 64;
const MAX_LEN_OF_ALL_PAIRS: usize = 8192;
  • Maximum entries: 64 key-value pairs
  • Maximum size: 8192 bytes total

Basic usage

Creating baggage

use opentelemetry::baggage::Baggage;

let mut baggage = Baggage::new();
baggage.insert("user.id", "12345");
baggage.insert("tenant.name", "acme-corp");
baggage.insert("feature.flag", "experimental");

Reading baggage

if let Some(user_id) = baggage.get("user.id") {
    println!("User ID: {}", user_id);
}

Baggage with metadata

use opentelemetry::baggage::{Baggage, BaggageMetadata};

let mut baggage = Baggage::new();
let metadata = BaggageMetadata::from("ttl=3600");
baggage.insert_with_metadata("session.id", "abc-123", metadata);

// Retrieve with metadata
if let Some((value, metadata)) = baggage.get_with_metadata("session.id") {
    println!("Session: {}, Metadata: {:?}", value, metadata);
}

BaggageExt trait

The BaggageExt trait extends Context with baggage management:
use opentelemetry::Context;
use opentelemetry::baggage::BaggageExt;

// Get baggage from context
let cx = Context::current();
let baggage = cx.baggage();

// Create context with baggage
let mut new_baggage = Baggage::new();
new_baggage.insert("request.id", "req-789");
let cx = cx.with_baggage(new_baggage);

Propagation

Baggage automatically propagates when using the BaggagePropagator:
use opentelemetry::global;
use opentelemetry::propagation::TextMapCompositePropagator;
use opentelemetry_sdk::propagation::{BaggagePropagator, TraceContextPropagator};

// Configure propagator to include baggage
let propagator = TextMapCompositePropagator::new(vec![
    Box::new(TraceContextPropagator::new()),
    Box::new(BaggagePropagator::new()),
]);

global::set_text_map_propagator(propagator);

Complete example

Service A (upstream)

use opentelemetry::{
    baggage::{Baggage, BaggageExt},
    global,
    trace::{Tracer, TraceContextExt},
    Context, KeyValue,
};
use std::collections::HashMap;

fn make_request() {
    let tracer = global::tracer("service-a");
    let mut span = tracer.start("process_request");
    
    // Create baggage
    let mut baggage = Baggage::new();
    baggage.insert("user.id", "12345");
    baggage.insert("request.source", "mobile-app");
    
    // Attach to context
    let cx = Context::current()
        .with_span(span)
        .with_baggage(baggage);
    
    // Inject into HTTP headers
    let mut headers = HashMap::new();
    global::get_text_map_propagator(|propagator| {
        propagator.inject_context(&cx, &mut headers);
    });
    
    // Send request with headers
    send_http_request(&headers);
}

Service B (downstream)

use opentelemetry::{
    baggage::BaggageExt,
    global,
    trace::{Tracer, TraceContextExt},
    KeyValue,
};
use std::collections::HashMap;

fn handle_request(headers: HashMap<String, String>) {
    // Extract context from headers
    let parent_cx = global::get_text_map_propagator(|propagator| {
        propagator.extract(&headers)
    });
    
    // Read baggage
    let baggage = parent_cx.baggage();
    
    let tracer = global::tracer("service-b");
    let mut span = tracer
        .span_builder("handle_request")
        .start_with_context(&tracer, &parent_cx);
    
    // Add baggage values as span attributes
    if let Some(user_id) = baggage.get("user.id") {
        span.set_attribute(KeyValue::new("user.id", user_id.to_string()));
    }
    
    if let Some(source) = baggage.get("request.source") {
        span.set_attribute(KeyValue::new("request.source", source.to_string()));
    }
    
    // Process request...
    span.end();
}

Common use cases

1. User identification

let mut baggage = Baggage::new();
baggage.insert("user.id", "12345");
baggage.insert("user.email", "[email protected]");
baggage.insert("user.role", "admin");

2. Request tracking

let mut baggage = Baggage::new();
baggage.insert("request.id", generate_request_id());
baggage.insert("correlation.id", correlation_id);

3. Feature flags

let mut baggage = Baggage::new();
baggage.insert("feature.new_ui", "enabled");
baggage.insert("experiment.variant", "b");

4. Multi-tenancy

let mut baggage = Baggage::new();
baggage.insert("tenant.id", "tenant-123");
baggage.insert("tenant.tier", "enterprise");

Iterating over baggage

use opentelemetry::baggage::Baggage;

let mut baggage = Baggage::new();
baggage.insert("key1", "value1");
baggage.insert("key2", "value2");

// Iterate over entries
for (key, (value, metadata)) in baggage.iter() {
    println!("{}: {} (metadata: {:?})", key, value, metadata);
}

Adding baggage to telemetry

Add to spans

use opentelemetry::{baggage::BaggageExt, trace::TraceContextExt, Context, KeyValue};

let cx = Context::current();
let baggage = cx.baggage();
let span = cx.span();

// Add all baggage as span attributes
for (key, (value, _)) in baggage.iter() {
    span.set_attribute(KeyValue::new(key.to_string(), value.to_string()));
}

Add to metrics

use opentelemetry::{baggage::BaggageExt, Context, KeyValue};

let cx = Context::current();
let baggage = cx.baggage();

let mut attributes = vec![];
if let Some(tenant) = baggage.get("tenant.id") {
    attributes.push(KeyValue::new("tenant.id", tenant.to_string()));
}

counter.add(&cx, 1, &attributes);

Best practices

Keep baggage small - Baggage is sent with every request. Keep the size minimal to avoid network overhead.
No sensitive data - Baggage propagates across all services and may be logged. Never put passwords, tokens, or PII in baggage.
Explicit attachment - Remember that baggage values don’t automatically appear in telemetry. You must explicitly read and attach them.
Validation - Baggage keys must follow RFC2616 token format. Invalid keys are rejected.

Baggage vs span attributes

FeatureBaggageSpan Attributes
PropagationAcross servicesWithin span only
VisibilityAll downstream servicesCurrent span
Size limits64 entries, 8KB totalNo hard limit
Automatic attachmentNoYes (to span)
Use caseCross-cutting concernsSpan-specific data

Propagators

Configure context propagation

Context propagation

Learn about context flow

Build docs developers (and LLMs) love