The formula, and where it comes from
Prometheus's own storage documentation gives capacity planning as one line:
needed_disk_space = retention_time_seconds * ingested_samples_per_second * bytes_per_sample
Two of those three terms are entirely about your own instrumentation, not about Prometheus itself.
ingested_samples_per_second is active series divided by scrape interval — and active
series is the product of every metric's label cardinalities, multiplied by however many targets expose
it, summed across every metric you run. There is no way to look that number up for “a typical
Prometheus deployment,” because it does not exist independent of what you have chosen to
instrument. The calculator above exists because this half of the formula has to be computed from your
specific metrics, not looked up.
The third term, bytes_per_sample, is the one genuinely general figure in the formula,
and Prometheus states it directly: “Prometheus stores an average of only 1-2 bytes per
sample.” That range comes from Gorilla-style delta-of-delta compression on chunks of
slowly-changing values, which is genuinely effective for typical metrics — counters that increase
steadily, gauges that drift gently — but is an average under favourable conditions, not a
constant. Highly volatile values compress worse. That is why this tool keeps it as an input with a
cited default of 1.3 rather than hard-coding either end of the range as fact.
The term the official formula doesn't itemise: the index
Sample bytes are not the whole disk picture. Every series, however few samples it has contributed, needs an entry in the index that maps its label combination to the chunks holding its data. Prometheus's capacity-planning formula is specifically about sample storage and does not break the index out as a separate line, but the cost is real, and it scales with how many distinct series have existed over the retention window — including ones that stopped being active partway through, a phenomenon usually called churn — rather than with how many samples those series produced.
This matters most exactly when it is least visible: a Kubernetes deployment with autoscaling or frequent rolling restarts can have a modest, stable active series count at any given moment while still accumulating a much larger number of distinct series over a 30-day retention window, each contributing its own index entry that outlives the series itself until compaction eventually reclaims it. This tool models that with a churn multiplier: a value of 3 treats the index as if three times as many distinct series existed as are active at any one instant, while leaving the sample-bytes calculation (which depends on ingestion rate, not on distinct-series-ever-seen) untouched. That is why index bytes and sample bytes are shown as two separate numbers above rather than combined into one — they respond to different things, and collapsing them would hide which one is actually driving your disk usage.
How Prometheus actually writes these bytes to disk
The formula above gives a total, but the way Prometheus reaches that total on disk explains a few
things that a single number can't. Ingested samples are grouped into two-hour blocks;
each block is a directory holding a chunks subdirectory with the compressed sample data, an index
file, and metadata — this is the unit the bytes_per_sample figure describes. The
current, not-yet-complete block lives in memory, which is why Prometheus also maintains a
write-ahead log (WAL): uncompacted, unsorted data written in 128 MB segments,
kept so that a crash before a block is finalised doesn't lose the data it holds. Prometheus's own
documentation notes it keeps a minimum of three WAL segments, with busier servers retaining more to
cover at least two hours of raw data — and because this data is uncompacted, the WAL directory
is typically far larger, byte for byte, than the compacted blocks holding the same time range.
Those two-hour blocks don't stay two hours forever. A background compaction process merges them into progressively larger blocks, and Prometheus states the limit directly: compaction “will create larger blocks containing data spanning up to 10% of the retention time, or 31 days, whichever is smaller.” This is why the disk usage of a fresh Prometheus instance and one that has been running for months at the same series count can look different even at an identical sample volume — compaction is still catching up on the newer one.
Retention itself has a second configuration path beyond the time-based
--storage.tsdb.retention.time flag this whole page assumes: --storage.tsdb.retention.size
caps total storage by bytes instead of by age, deleting the oldest blocks first once the cap is
reached, and whichever limit is hit first wins if both are set. Prometheus's own recommendation is to
set that size cap to at most 80–85% of the disk actually allocated to leave
headroom for the current in-progress block and WAL, which are not counted against the size limit the
same way completed blocks are. If you know your disk size before you know your retention period,
sizing by retention.size rather than retention.time is often the more direct
way to stay within it.
One more detail worth knowing if a number here doesn't match what du reports on a real
server: deleting series through the API doesn't reclaim space immediately. Deletions are recorded as
tombstones rather than rewriting chunk files in place, and expired-block cleanup runs in the
background and can take up to two hours to actually remove a block once it has fully expired. A
Prometheus instance can legitimately be holding slightly more on disk than its retention setting
implies for a short window, and that is expected behaviour, not a leak.
Retention and scrape interval, worked through
Two levers are entirely within an operator's control without touching instrumentation at all:
Retention period
A direct multiplier on total samples and sample bytes: doubling retention from 15 to 30 days doubles both, with active series and samples-per-second completely unchanged. Retention is usually the first lever operators reach for when disk runs short, and it is the most predictable one — the relationship is exact, not approximate, so halving retention to recover disk headroom has a fully calculable effect before you make the change.
Scrape interval
Doubling the scrape interval (scraping half as often) halves samples per second and, proportionally, halves total samples and sample bytes over the same retention window. It does nothing to active series or index bytes, since those count distinct series, not how frequently each is sampled. The real cost is resolution: a 60-second interval will not capture a 10-second spike the way a 15-second interval would, which matters enormously for some alerting use cases and not at all for others. This is a trade-off to make with the specific metric's purpose in mind, not a default to change blindly for disk savings.
A worked comparison
Using the estimator's default 1.3 bytes/sample and 100 index-bytes/series, holding 19,260 active series constant (the small healthy-cluster example from the main tool page) and varying only retention and scrape interval:
| Scenario | Scrape interval | Retention | Samples/sec | Estimated disk |
|---|---|---|---|---|
| Baseline | 15s | 15d | 1,284 | 2.17 GB |
| Double the retention | 15s | 30d | 1,284 | 4.33 GB |
| Double the scrape interval | 30s | 15d | 642 | 1.08 GB |
Doubling retention roughly doubles disk; doubling the scrape interval roughly halves it — both exactly what the formula predicts, and both leaving active series (and therefore memory and query cost) completely unaffected, because neither lever touches how many distinct series exist.
Beyond a single instance
Prometheus's storage model, and the formula above, describe one server writing to its own local
disk, with no built-in replication and retention bounded by how much of that disk it can use. For
requirements beyond that — multi-year retention, durability across node loss, a single query
surface across many Prometheus servers — the standard pattern is remote_write to a
long-term storage backend designed for exactly that, with the local instance keeping only a short
buffer window on fast local disk. That is a deliberate architectural decision with its own operational
trade-offs, not a configuration flag, and sits outside what a single-instance calculator like this one
can estimate.
Frequently asked questions
What is Prometheus's own formula for disk space?
Prometheus's storage documentation gives it directly:
needed_disk_space = retention_time_seconds * ingested_samples_per_second * bytes_per_sample.
This tool's first two steps — active series divided by scrape interval, then multiplied by
retention — compute exactly the retention_time_seconds * ingested_samples_per_second
half of that formula, then multiply by an adjustable bytes-per-sample and add a separate
index-overhead term the official formula does not itemise on its own.
Does doubling retention double my disk usage?
For the sample-bytes portion, yes, exactly — it is a direct multiplication in the formula, so twice the retention time with everything else held constant is twice the samples, and twice the sample bytes. Index bytes behave differently: they scale with the number of distinct series that have existed over the window (including churned ones), which grows with retention too, but not necessarily in exact proportion, since a longer window captures more distinct churned series without those adding proportionally more index cost per series.
Should I lower my scrape interval to save disk?
Increasing the scrape interval (scraping less often) does reduce samples per second and therefore total samples and sample bytes proportionally — doubling the interval halves both. It does not reduce active series or index bytes at all, since those depend on how many distinct series exist, not how often each is sampled. The trade-off is resolution: a longer interval means less granular data, which can hide short-lived spikes that a shorter interval would have captured. This is a genuine trade-off to make deliberately, not a free optimisation.
What happens when local disk isn't enough?
Prometheus's own model assumes local disk on the same node running the server, which does not
scale indefinitely and has no built-in replication. For retention beyond what local disk can hold, or
for durability across node failure, the common pattern is remote_write to a long-term
storage backend built for that purpose, with the local Prometheus instance keeping only a short
buffer window. That is a deliberate architectural change, not a setting to flip, and is outside the
single-instance model this calculator estimates.
Why does this tool add an index-bytes term the official formula doesn't mention?
Prometheus's own capacity-planning formula is explicitly about sample storage, and its bytes-per-sample figure describes chunk-compressed sample data specifically. It does not itemise the separate cost of the index that maps label combinations to those chunks. That index cost is real and, under heavy series churn, can be a meaningful fraction of total disk — so this tool adds it back as an explicit, separately-labelled second term rather than silently folding it into bytes-per-sample and quietly overstating how solid that cited figure is.
- The full cardinality & storage estimatorAdd your own metrics and see active series, samples/sec and disk together
- What is high cardinality in Prometheus?Why label combinations explode, and how to find the label responsible
- About this toolHow the maths is built and cross-checked