Grafana Tempo replaces costly APM tracing SaaS like Honeycomb by streaming OpenTelemetry spans into cheap object storage using Apache Parquet.
Commercial tracing platforms like Honeycomb price by event volume, forcing teams to discard most spans through aggressive sampling. Grafana Tempo strips out dedicated index databases and writes raw traces straight to object storage in Apache Parquet format. By eliminating per-event SaaS fees and database maintenance, it allows organizations to retain complete request telemetry on their own infrastructure.
Honeycomb delivers sub-second queries across high-cardinality attributes using an in-memory columnar engine, but that speed comes chained to event pricing. When distributed systems generate millions of spans hourly, teams must drop ninety percent or more of their traces to control bills. Grafana Tempo prioritizes write throughput over instant indexing. By streaming spans directly into columnar Apache Parquet files on object storage and buffering writes through Kafka with single replication, Tempo sustains high ingestion volumes with minimal compute overhead. Teams retain all traces rather than gambling on head-based sampling.
The performance trade-off appears during retrieval. Honeycomb evaluates arbitrary exploratory queries almost instantly, whereas Tempo executes TraceQL by fanning out worker processes across object storage blocks. Fetching a trace by identifier or jumping from a Prometheus exemplar takes milliseconds, but broad queries across wide windows require streaming Parquet blocks over the network and consume noticeable CPU. For teams already running Prometheus and Loki, Tempo provides predictable operational costs and ample ingestion headroom in exchange for slower deep scans.
Can Grafana Tempo run without Elasticsearch or Cassandra? Yes. Tempo persists trace blocks directly to object storage such as AWS S3, Google Cloud Storage, or MinIO, requiring no separate search database.
Grafana Tempo vs Honeycomb — which should you choose? Choose Honeycomb for managed SaaS with sub-second exploratory querying across sampled events; choose Tempo to self-host, retain one hundred percent of traces, and avoid event volume fees.
Is Grafana Tempo compatible with OpenTelemetry? Yes. Tempo natively accepts OpenTelemetry protocol (OTLP) data over gRPC and HTTP, so instrumented services can send spans directly without adapters.
Grafana Tempo is ideal for organizations that need complete trace retention and predictable infrastructure costs without managing complex search clusters. Maintained actively by Grafana Labs with ongoing commits in late 2026, the backend is published under the AGPL-3.0 license, which secures data ownership internally while requiring vendors distributing modified hosted forks to contribute changes back. Teams comfortable querying via TraceQL and Grafana will find it an exceptionally efficient tracing tier.
Commands from the official package registries. Each package is matched to Grafana Tempo through the registry's own link to its source code or website.
sudo pacman -S tempoWe started this exact setup from scratch in a clean Linux machine on Nov 3, 2026 and checked it through Grafana Tempo's own API: every check passed. Recipes are re-checked regularly and removed if they stop working.
mkdir -p tempo && cd tempo
curl -fsSL https://open-source.store/tools/tempo/compose.yml -o compose.ymltouch .envdocker compose up -dservices:
tempo:
image: grafana/tempo:3.1.1
command: ["-config.file=/etc/tempo.yaml"]
ports:
- "127.0.0.1:3200:3200"
- "127.0.0.1:4317:4317"
- "127.0.0.1:4318:4318"
volumes:
- tempo-data:/var/tempo
configs:
- source: tempo_config
target: /etc/tempo.yaml
restart: always
healthcheck:
test: ["CMD", "/tempo", "-health"]
interval: 10s
timeout: 5s
retries: 5
start_period: 10s
configs:
tempo_config:
content: |
stream_over_http_enabled: true
server:
http_listen_port: 3200
log_level: info
distributor:
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
http:
endpoint: 0.0.0.0:4318
storage:
trace:
backend: local
wal:
path: /var/tempo/wal
local:
path: /var/tempo/blocks
usage_report:
reporting_enabled: false
volumes:
tempo-data: {}
Go, gRPC and Protobuf done right, LLM agents in production, and the hard parts of shipping a first product.
Show that Grafana Tempo is listed as an open-source alternative. Paste into your README:
Ubuntu 24.04 · Apple container, Docker 29.1.3, Compose 2.40.3+ds1-0ubuntu1~24.04.1. Images pulled in 7 s: grafana/tempo:3.1.1.
Based on the upstream setup. Official single-binary example with local filesystem storage. Image pinned to 3.1.1, ports bound to 127.0.0.1 because Tempo has no native authentication, and built-in healthcheck enabled.
tempo-1 | 2026-11-03T01:29:28.089289587Z level=info ts=2026-11-03T01:29:28.089033045Z caller=main.go:105 msg="Starting Tempo" version="(version=v3.1.1, branch=HEAD, revision=9db7df79d)" target=all tempo-1 | 2026-11-03T01:29:28.089302087Z level=info ts=2026-11-03T01:29:28.089203962Z caller=cache.go:90 msg="caches available to storage backend" parquet-footer=false bloom=false parquet-offset-idx=false parquet-column-idx=false trace-id-index=false parquet-page=false tempo-1 | 2026-11-03T01:29:28.089734545Z level=info ts=2026-11-03T01:29:28.089693212Z caller=server.go:296 msg="server listening on addresses" http=[::]:3200 grpc=[::]:9095 tempo-1 | 2026-11-03T01:29:28.090159045Z level=warn ts=2026-11-03T01:29:28.09013317Z caller=modules.go:687 msg="Scheduler address is empty in single binary mode. Attempting automatic worker configuration." address=127.0.0.1:9095 tempo-1 | 2026-11-03T01:29:28.090175379Z level=info ts=2026-11-03T01:29:28.09014817Z caller=backendworker.go:81 msg="backend worker starting" worker_id=f08b690f4dd0 tempo-1 | 2026-11-03T01:29:28.090341212Z level=warn ts=2026-11-03T01:29:28.090319629Z caller=modules.go:409 msg="Worker address is empty in single binary mode. Attempting automatic worker configuration. If queries are unresponsive consider configuring the worker explicitly." address=127.0.0.1:9095 tempo-1 | 2026-11-03T01:29:28.090397212Z level=info ts=2026-11-03T01:29:28.090373587Z caller=worker.go:108 msg="Starting querier worker connected to query-frontend" frontend=127.0.0.1:9095 tempo-1 | 2026-11-03T01:29:28.090445629Z level=warn ts=2026-11-03T01:29:28.090434045Z caller=modules.go:304 msg="metrics-generator is not configured." err="no metrics_generator.storage.path configured, metrics generator will be disabled" tempo-1 | 2026-11-03T01:29:28.090521170Z level=info ts=2026-11-03T01:29:28.090501712Z caller=frontend.go:88 msg="creating middleware in query frontend" tempo-1 | 2026-11-03T01:29:28.090539504Z level=info ts=2026-11-03T01:29:28.090522212Z caller=sync_handler_cache.go:131 msg="init frontend cache" role=frontend-search enabled=false tempo-1 | 2026-11-03T01:29:28.090540504Z level=info ts=2026-11-03T01:29:28.090535545Z caller=sync_handler_cache.go:131 msg="init frontend cache" role=frontend-search enabled=false tempo-1 | 2026-11-03T01:29:28.090549004Z level=info ts=2026-11-03T01:29:28.090540212Z caller=sync_handler_cache.go:131 msg="init frontend cache" role=frontend-search enabled=false tempo-1 | 2026-11-03T01:29:28.090550920Z level=info ts=2026-11-03T01:29:28.09054717Z caller=sync_handler_cache.go:131 msg="init frontend cache" role=frontend-search enabled=false tempo-1 | 2026-11-03T01:29:28.090566129Z level=info ts=2026-11-03T01:29:28.090551587Z caller=sync_handler_cache.go:131 msg="init frontend cache" role=frontend-search enabled=false tempo-1 | 2026-11-03T01:29:28.090579045Z level=info ts=2026-11-03T01:29:28.090558504Z caller=sync_handler_cache.go:131 msg="init frontend cache" role=frontend-search enabled=false tempo-1 | 2026-11-03T01:29:28.090749962Z ts=2026-11-03T01:29:28Z level=info msg="OTel Shim Logger Initialized" component=tempo tempo-1 | 2026-11-03T01:29:28.091201837Z level=info ts=2026-11-03T01:29:28.091114504Z caller=module_service.go:82 msg=starting module=internal-server tempo-1 | 2026-11-03T01:29:28.091203420Z level=info ts=2026-11-03T01:29:28.09115017Z caller=module_service.go:82 msg=starting module=cache-provider tempo-1 | 2026-11-03T01:29:28.091204045Z level=info ts=2026-11-03T01:29:28.091180754Z caller=module_service.go:82 msg=starting module=store tempo-1 | 2026-11-03T01:29:28.091230420Z level=info ts=2026-11-03T01:29:28.091213587Z caller=module_service.go:82 msg=starting module=server tempo-1 | 2026-11-03T01:29:28.091461129Z level=info ts=2026-11-03T01:29:28.091436629Z caller=module_service.go:82 msg=starting module=memberlist-kv tempo-1 | 2026-11-03T01:29:28.091509087Z level=info ts=2026-11-03T01:29:28.091489712Z caller=module_service.go:82 msg=starting module=overrides tempo-1 | 2026-11-03T01:29:28.091677629Z level=info ts=2026-11-03T01:29:28.091648212Z caller=module_service.go:82 msg=starting module=overrides-api tempo-1 | 2026-11-03T01:29:28.091730587Z level=info ts=2026-11-03T01:29:28.09171042Z caller=module_service.go:82 msg=starting module=backend-scheduler tempo-1 | 2026-11-03T01:29:28.091744837Z level=info ts=2026-11-03T01:29:28.091715212Z caller=backendscheduler.go:134 msg="backend scheduler starting" tempo-1 | 2026-11-03T01:29:28.091762004Z level=info ts=2026-11-03T01:29:28.091751254Z caller=module_service.go:82 msg=starting module=query-frontend tempo-1 | 2026-11-03T01:29:28.092066337Z level=info ts=2026-11-03T01:29:28.09204117Z caller=backendscheduler.go:221 msg="backend scheduler running" tempo-1 | 2026-11-03T01:29:28.092252712Z level=info ts=2026-11-03T01:29:28.092218045Z caller=module_service.go:82 msg=starting module=metrics-generator tempo-1 | 2026-11-03T01:29:28.092254462Z level=info ts=2026-11-03T01:29:28.092232337Z caller=module_service.go:82 msg=starting module=live-store-ring tempo-1 | 2026-11-03T01:29:28.092299920Z level=info ts=2026-11-03T01:29:28.092272337Z caller=ring.go:390 msg="ring doesn't exist in KV store yet" tempo-1 | 2026-11-03T01:29:28.092345212Z level=info ts=2026-11-03T01:29:28.092320045Z caller=compaction.go:96 msg="compaction provider started" tempo-1 | 2026-11-03T01:29:28.092346504Z level=info ts=2026-11-03T01:29:28.092325379Z caller=compaction.go:120 msg="compaction provider waiting for poll notification" tempo-1 | 2026-11-03T01:29:28.092347129Z level=info ts=2026-11-03T01:29:28.092329837Z caller=retention.go:56 msg="retention provider started" tempo-1 | 2026-11-03T01:29:28.092355462Z level=info ts=2026-11-03T01:29:28.092339879Z caller=redaction.go:60 msg="redaction provider started" tempo-1 | 2026-11-03T01:29:28.092382129Z level=info ts=2026-11-03T01:29:28.092365212Z caller=module_service.go:82 msg=starting module=partition-ring tempo-1 | 2026-11-03T01:29:28.092408337Z level=info ts=2026-11-03T01:29:28.092391087Z caller=partition_ring_watcher.go:85 msg="partition ring doesn't exist in KV store yet" tempo-1 | 2026-11-03T01:29:28.092435962Z level=info ts=2026-11-03T01:29:28.092419129Z caller=module_service.go:82 msg=starting module=querier tempo-1 | 2026-11-03T01:29:28.092613129Z level=info ts=2026-11-03T01:29:28.09258967Z caller=module_service.go:82 msg=starting module=live-store tempo-1 | 2026-11-03T01:29:28.092833295Z level=info ts=2026-11-03T01:29:28.092056087Z caller=module_service.go:82 msg=starting module=backend-worker tempo-1 | 2026-11-03T01:29:28.093044004Z level=info ts=2026-11-03T01:29:28.093021337Z caller=live_store_background.go:322 msg="reloading wal blocks" tempo-1 | 2026-11-03T01:29:28.093169795Z level=warn ts=2026-11-03T01:29:28.093131129Z caller=wal.go:101 msg="unowned file entry ignored during wal replay" file=blocks err=null tempo-1 | 2026-11-03T01:29:28.093171754Z level=info ts=2026-11-03T01:29:28.09314367Z caller=live_store_background.go:357 msg="wal blocks to complete at startup" count=0 tempo-1 | 2026-11-03T01:29:28.093176087Z level=info ts=2026-11-03T01:29:28.093148254Z caller=live_store_background.go:362 msg="reloading completed blocks" tempo-1 | 2026-11-03T01:29:28.093176920Z level=info ts=2026-11-03T01:29:28.093157212Z caller=live_store_background.go:445 msg="done reloading completed blocks" tempo-1 | 2026-11-03T01:29:28.093182337Z level=info ts=2026-11-03T01:29:28.093163462Z caller=live_store.go:303 msg="deleting old blocks" tempo-1 | 2026-11-03T01:29:28.093183129Z level=info ts=2026-11-03T01:29:28.093169337Z caller=live_store.go:310 msg="done deleting old blocks" tempo-1 | 2026-11-03T01:29:28.093500170Z level=info ts=2026-11-03T01:29:28.093474587Z caller=partition_instance_lifecycler.go:287 ring=livestore-partitions msg="partition not found in the ring" partition=0 tempo-1 | 2026-11-03T01:29:28.093588629Z level=info ts=2026-11-03T01:29:28.09356642Z caller=basic_lifecycler.go:324 msg="instance not found in the ring" instance=f08b690f4dd0 ring=live-store tempo-1 | 2026-11-03T01:29:28.093611629Z level=info ts=2026-11-03T01:29:28.093589879Z caller=live_store.go:341 msg="starting all background processes" tempo-1 | 2026-11-03T01:29:28.093612879Z level=info ts=2026-11-03T01:29:28.093598962Z caller=live_store.go:344 msg="waiting for ingestion catching up" tempo-1 | 2026-11-03T01:29:28.093613587Z level=info ts=2026-11-03T01:29:28.093601212Z caller=live_store.go:348 msg="done waiting for ingestion catching up" tempo-1 | 2026-11-03T01:29:28.093619587Z level=info ts=2026-11-03T01:29:28.093605337Z caller=live_store.go:353 msg="live-store ready to serve queries" tempo-1 | 2026-11-03T01:29:28.093635837Z level=info ts=2026-11-03T01:29:28.09362242Z caller=module_service.go:82 msg=starting module=distributor tempo-1 | 2026-11-03T01:29:28.093721420Z ts=2026-11-03T01:29:28Z level=info msg="Starting GRPC server" component=tempo endpoint=[::]:4317 tempo-1 | 2026-11-03T01:29:28.093737087Z ts=2026-11-03T01:29:28Z level=info msg="Starting HTTP server" component=tempo endpoint=[::]:4318 tempo-1 | 2026-11-03T01:29:28.093802754Z level=info ts=2026-11-03T01:29:28.093768712Z caller=worker.go:184 msg="adding connection" addr=127.0.0.1:9095 tempo-1 | 2026-11-03T01:29:28.093922337Z level=info ts=2026-11-03T01:29:28.093876045Z caller=live_store_background.go:83 msg="starting completing loop" index=0 tempo-1 | 2026-11-03T01:29:28.093924087Z level=info ts=2026-11-03T01:29:28.09388542Z caller=live_store_background.go:83 msg="starting completing loop" index=1 tempo-1 | 2026-11-03T01:29:28.094496795Z level=info ts=2026-11-03T01:29:28.094466045Z caller=worker.go:250 msg="total worker concurrency updated" totalConcurrency=20 tempo-1 | 2026-11-03T01:29:28.094641129Z level=info ts=2026-11-03T01:29:28.092791045Z caller=tempodb.go:840 msg="polling enabled" interval=5m0s blocklist_concurrency=50 tempo-1 | 2026-11-03T01:29:28.094700879Z level=info ts=2026-11-03T01:29:28.094653129Z caller=poller.go:249 msg="blocklist poll complete" seconds=2.95e-05 tempo-1 | 2026-11-03T01:29:28.094702004Z level=info ts=2026-11-03T01:29:28.094670045Z caller=backendworker.go:184 msg="backend worker running" tempo-1 | 2026-11-03T01:29:28.095073379Z level=info ts=2026-11-03T01:29:28.095042045Z caller=compaction.go:136 msg="received empty tenant" tempo-1 | 2026-11-03T01:29:28.095153629Z level=info ts=2026-11-03T01:29:28.095128587Z caller=app.go:218 msg="Tempo started" tempo-1 | 2026-11-03T01:29:28.175738295Z 2026/11/03 01:29:28 http: superfluous response.WriteHeader call from go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/internal/request.(*RespWriterWrapper).writeHeader (resp_writer_wrapper.go:90) tempo-1 | 2026-11-03T01:29:28.176298462Z level=info ts=2026-11-03T01:29:28.176257295Z caller=search_handlers.go:243 msg="search request" tenant=single-tenant query= range_seconds=0 limit=0 spans_per_spanset=3 tempo-1 | 2026-11-03T01:29:28.178250254Z level=info ts=2026-11-03T01:29:28.17817492Z caller=util.go:147 msg="search response" tenant=single-tenant traceID= query= range_seconds=0 duration_seconds=0.00192875 request_throughput=0 total_requests=3 total_blockBytes=0 total_blocks=0 completed_requests=3 inspected_bytes=0 inspected_traces=0 inspected_spans=0 status_code=200 error=null query_type=search query_weight=1 query_sub_queries=0 query_conditions=0 query_regex_conditions=0 query_has_or=false query_needs_full_trace=false query_select_all=false tempo-1 | 2026-11-03T01:29:28.178255504Z level=info ts=2026-11-03T01:29:28.17819767Z caller=handler.go:139 msg="query stats" tenant=single-tenant method=GET traceID= url="/api/search?end=1793669338&start=1793668468" duration=1.953916ms response_size=57 status=200