OpenTelemetry Span Kinds
Last updated: May 21, 2026
The span kind describes the role of a span in a distributed trace.
It helps observability tools understand whether a span represents:
work happening inside a service,
an incoming request,
an outgoing request,
a message being produced,
or a message being consumed.
Choosing the right span kind makes traces easier to read and helps build accurate service maps, dependency graphs, and latency breakdowns.
Server
A server span represent the handling of a synchronous inbound request on a service. This means another service, browser, CLI, or external system called this service and is waiting for a response.
Common examples:
receiving an HTTP request,
handling a gRPC call,
processing an incoming RPC request.
A server span often has a corresponding client span on the caller side (if that caller service is instrumented with tracing).
Example
API receives GET /users/123Span kind:
server
Client
A client span represents an outbound request to another service.
This usually means the current service is calling a remote system and waiting for a response.
Common examples:
making an HTTP request,
calling a gRPC service,
querying a database,
calling an external API.
A client span often has a corresponding server span on the receiving side (if that callee service is instrumented)
Example
API calls the user-serviceSpan kind:
client
Producer
A producer span represents sending or publishing a message to a broker, queue, topic, or stream.
This is used for asynchronous communication. The producer usually does not wait for the full processing of the message to finish.
Common examples:
publishing a Kafka message,
sending a message to RabbitMQ,
writing an event to a queue,
pushing a job to a background worker system.
Unlike client and server, producer and consumer spans do not usually represent a direct request/response latency relationship. The producer span may end long before the consumer starts processing the message.
Example
Checkout service publishes OrderCreatedSpan kind:
producer
Consumer
A consumer span represents receiving or processing a message from a broker, queue, topic, or stream.
This is the other side of asynchronous communication.
Common examples:
consuming a Kafka message,
reading from RabbitMQ,
processing a queued job,
handling an event from a stream.
A consumer span is typically related to a previous producer span, but it may happen later and in a different trace shape than a normal synchronous request.
Example
Email service consumes OrderCreated and sends a confirmation emailSpan kind:
consumer
Internal
An internal span represents an operation that does not cross a process boundary. The span represents work happening inside a service, without directly representing communication with another system.
This is the default span kind when no explicit kind is provided.
Common examples:
validating input,
rendering a template,
calculating a price,
running business logic,
reading from an in-memory cache,
executing an internal function.
Use internal for spans that help explain what happened inside a service, but are not themselves incoming requests, outgoing requests, produced messages, or consumed messages.
Example
Calculate cart totalSpan kind:
internal