Span
A single unit of work in a distributed trace, representing one operation (e.g., an HTTP call or database query). Spans are nested to form a trace tree.
What is Span?
In short
A span is a single timed unit of work inside a distributed trace, recording one operation such as an HTTP request, a database query, or a function call, along with its start time, duration, and metadata. Spans nest into a parent-child tree, and the full tree of spans for one request is called a trace.
What a span actually is
When a request flows through a distributed system, it touches many services: an API gateway, a few backend services, a cache, a database. A span captures one of those steps. It is the basic building block of distributed tracing, the same way a single line is the building block of a log file.
Every span carries a small set of standard fields. It has a name that describes the operation (for example GET /checkout or SELECT orders), a start timestamp, a duration, a span ID that uniquely identifies it, and a trace ID shared by every span in the same request. Most spans also have a parent span ID that points to the span that triggered them, which is how the tree gets built.
On top of those core fields, a span holds attributes (key-value tags like http.status_code=200 or db.system=postgresql), events (timestamped notes such as an exception being thrown), and a status that marks whether the operation succeeded or failed. In OpenTelemetry, which is the standard most tools now follow, all of this is defined in the span data model.
How spans connect into a trace
A single request produces many spans, and they all share one trace ID. The first span, created when the request enters the system, is the root span and has no parent. Every span created downstream records the ID of the span that called it as its parent. Following those parent links from the root downward gives you a tree.
The hard part is passing the trace ID and the current span ID across the network when one service calls another. This is called context propagation. With HTTP, the standard way is the W3C Trace Context header, traceparent, which looks like 00-<trace-id>-<span-id>-01 and rides along on every outbound request. The receiving service reads it, starts a child span, and the chain continues.
Because every span records its own start time and duration, the trace tree doubles as a timeline. You can see that the request took 800ms total, that 600ms of it was a single slow database span, and that two downstream calls ran in parallel rather than one after the other. That waterfall view is the main reason teams adopt tracing.
When to use spans and the trade-offs
Spans are most useful when a single request crosses several services and you cannot tell from logs alone where the time went or where it failed. Microservice architectures, serverless fan-out, and any system with deep call chains benefit the most. For a small monolith with one database, tracing adds overhead without much payoff.
The main cost is volume. A busy service can emit millions of spans per minute, and storing all of them is expensive. The usual answer is sampling: keep a percentage of traces (head sampling, decided up front) or keep only the interesting ones such as errors and slow requests (tail sampling, decided after the trace finishes). Tail sampling is more accurate but needs to buffer spans until the trace completes.
Two practical pitfalls show up often. First, instrumenting too finely creates thousands of tiny spans per request and buries the signal, so span the meaningful boundaries, not every function. Second, broken context propagation produces orphan spans that never join their parent trace, usually because a header was dropped at a proxy, a message queue, or an async job boundary.
A concrete example
Picture an e-commerce checkout. A user clicks Pay. The frontend calls the order service, which creates the root span named POST /checkout with a fresh trace ID. The order service then calls the inventory service, the payment service, and writes to its own database.
Each of those calls becomes a child span: inventory.reserve, payment.charge, and db.insert order. The payment span itself makes an outbound call to Stripe, producing a grandchild span. If Stripe is slow and takes 1.2 seconds, that single span lights up red in the waterfall and you immediately know the bottleneck is the payment provider, not your own code or database.
When the request finishes, all five or six spans share the same trace ID and form one tree. An engineer opening that trace in Jaeger or Grafana Tempo sees the full story of one checkout in a single view, instead of stitching together log lines from five different services by hand.
Where it is used in production
OpenTelemetry
Defines the vendor-neutral span data model and SDKs that nearly every modern tracing tool now produces and consumes.
Jaeger
Open-source tracing backend, originally from Uber, that ingests spans and renders the trace waterfall view.
Grafana Tempo
High-volume trace store that keeps spans cheaply in object storage like S3 and links them back to logs and metrics.
Datadog APM
Collects spans from instrumented services and uses them to build service maps, latency breakdowns, and error tracking.
Frequently asked questions
- What is the difference between a span and a trace?
- A span is one operation, like a single database query or HTTP call. A trace is the whole tree of spans for one request as it moves through every service. One trace contains many spans that all share the same trace ID.
- What is a root span?
- The root span is the first span created when a request enters the system. It has a trace ID but no parent span ID. Every other span in the trace descends from it, directly or indirectly.
- What information does a span contain?
- A name, a trace ID, its own span ID, usually a parent span ID, a start time, a duration, a status that marks success or failure, plus attributes (tags like http.status_code) and events (timestamped notes such as an exception).
- How do spans get linked across different services?
- Through context propagation. When one service calls another over HTTP, it sends the trace ID and current span ID in a header, typically the W3C traceparent header. The receiving service reads it and starts a child span, keeping the chain intact.
- Why are some traces only partly recorded?
- Because of sampling. To control cost, tracing systems keep only a fraction of traces. Head sampling decides up front by percentage, while tail sampling keeps the interesting ones such as errors and slow requests after the trace finishes.
Learn Span hands-on
This page explains the idea. The full lesson lets you step through the ring as servers join and leave, read the implementation, and check yourself with a quiz. It is one of 760+ lessons in the System Design Masterclass, from your first API call to distributed consensus. Eleven Foundation lessons are free, no signup. Lifetime access is ₹499 in India or $7.99 worldwide, one payment, no subscription.
Related lessons
Lessons that touch on Span as part of a larger topic.
Span IDs
Individual operations within a trace, each span is one unit of work with a start time, duration, and parent
intermediate · observability monitoring
NewSQL Databases
Distributed SQL databases that promise the scalability of NoSQL with the ACID guarantees of traditional SQL. CockroachDB, Google Spanner, and the NewSQL movement
intermediate · database types storage
Data Consistency Models
The full spectrum from eventual to strong, understand every model and when you need each one
advanced · consistency models
Global Tables
Fully replicated tables available in every region, low-latency reads worldwide with the trade-off of slower writes
intermediate · database types storage
LLM Observability and Tracing: Seeing Inside a Nondeterministic System
An LLM app fails behind a 200 OK: right status, wrong answer. Capture the rendered prompt, token split, and per-step latency on one trace id.
ml-advanced · llm genai ops
See also
Related glossary terms you might want to look up next.
Distributed Tracing
Tracking a request as it flows through multiple services in a distributed system. Each service adds its trace, creating a full picture of the request journey.
Trace
The full end-to-end path of a request through a distributed system, composed of multiple spans. A trace shows which services were called, in what order, and how long each took.
Observability
The ability to understand a system's internal state from its external outputs. Built on three pillars: metrics, logs, and traces.
Health Check
An endpoint or mechanism that reports whether a service is running and healthy. Load balancers use health checks to route traffic away from unhealthy instances.
Metrics
Numerical measurements collected over time that describe system behavior: request rate, error rate, latency percentiles, CPU utilization. Prometheus is the standard collector.
Logging
Recording discrete events with timestamps, severity levels, and context. Structured logs (JSON) are searchable; unstructured logs (plaintext) are not. Ship them to a central system.