These four are frequently presented as one stack, which obscures the useful information: they solve different problems, arrive at different points in an organisation's growth, and adopting all of them at once is a common and expensive mistake.
Prometheus is where you start and mostly stay
Prometheus collects and stores metrics, and its query language is the reason the rest of this ecosystem exists. For most teams it is sufficient on its own for a long time.
Its constraints are specific: storage is local to the instance, so retention is bounded by that disk, and it does not natively span clusters. Neither matters until you want to answer questions across a fleet or look back further than local retention allows. Plenty of estates never hit either limit.
Mimir is for when local storage is the constraint
Mimir provides long-term, horizontally scalable metric storage that many Prometheus instances write into, with one query interface across them.
You want it when you need retention measured in months rather than weeks, or a query spanning many clusters, or high availability that survives losing a Prometheus. Below that, it is a distributed system you are operating for benefits you are not consuming.
Adopt Mimir when local retention or cross-cluster queries are actually blocking you, not in anticipation.
Loki is logs, arranged like metrics
Loki indexes labels rather than log contents. That makes it dramatically cheaper to run than full-text search systems and changes how you use it: you narrow by label first, then grep within that stream.
If your workflow is to jump from a metric spike to the logs for that exact service and time window, the model fits and the cost saving is substantial. If you need arbitrary full-text search across everything without knowing the labels, you will find it frustrating and should use something built for that.
Tempo is traces, and answers a different question
Tempo stores distributed traces cheaply by not indexing them heavily, on the assumption you arrive with a trace ID from a log or an exemplar rather than searching blind.
Traces answer the question metrics cannot: in a request that touched nine services, which hop was responsible. That question only becomes pressing once your call graph is deep enough that the answer is not obvious, which is later than most teams assume.
The order that works
Metrics first, always. Then logs, correlated to those metrics by consistent labels. Then traces on the paths that generate incidents. Then long-term storage, once you know which of it you actually query.
Adopting all four at once means operating four systems while still learning what questions you need to ask, and it usually produces an expensive stack that answers the same questions Prometheus alone was answering.
The part that matters more than any of them
Consistent labelling across all of it. If a service is named one way in metrics and another in logs, moving between them requires human translation and you lose most of the value regardless of which components you run.
That is the argument for standardising on OpenTelemetry for instrumentation: one place to enforce naming, independent of language, runtime or which of these you are storing it in.



