In an ideal world (where your samples' timestamps are exactly on the second and your rule evaluation happens exactly on the second) rate(counter[1s]) would return exactly your ICH value and rate(counter[5s]) would return the average of that ICH and the previous 4. Except the ICH at second 1 is 0, not 1, because no one knows when your counter was zero: maybe it incremented right there, maybe it got incremented yesterday, and stayed at 1 since then. (This is the reason why you won't see an increase the first time a counter appears with a value of 1 -- because your code just created and incremented it.)

increase(counter[5s]) is exactly rate(counter[5s]) * 5 (and increase(counter[2s]) is exactly rate(counter[2s]) * 2).

Now what happens in the real world is that your samples are not collected exactly every second on the second and rule evaluation doesn't happen exactly on the second either. So if you have a bunch of samples that are (more or less) 1 second apart and you use Prometheus' rate(counter[1s]), you'll get no output. That's because what Prometheus does is it takes all the samples in the 1 second range [now() - 1s, now()] (which would be a single sample in the vast majority of cases), tries to compute a rate and fails.

If you query rate(counter[5s]) OTOH, Prometheus will pick all the samples in the range [now() - 5s, now] (5 samples, covering approximately 4 seconds on average, say [t1, v1], [t2, v2], [t3, v3], [t4, v4], [t5, v5]) and (assuming your counter doesn't reset within the interval) will return (v5 - v1) / (t5 - t1). I.e. it actually computes the rate of increase over ~4s rather than 5s.

increase(counter[5s]) will return (v5 - v1) / (t5 - t1) * 5, so the rate of increase over ~4 seconds, extrapolated to 5 seconds.

Due to the samples not being exactly spaced, both rate and increase will often return floating point values for integer counters (which makes obvious sense for rate, but not so much for increase).

Answer from Alin Sînpălean on Stack Overflow
🌐
Prometheus
prometheus.io › docs › prometheus › latest › querying › functions
Query functions | Prometheus
At the current stage, this is an ... info series and with their appropriate identifying labels. irate(v range-vector) calculates the per-second instant rate of increase of the time series in the range vector....
Top answer
1 of 3
273

In an ideal world (where your samples' timestamps are exactly on the second and your rule evaluation happens exactly on the second) rate(counter[1s]) would return exactly your ICH value and rate(counter[5s]) would return the average of that ICH and the previous 4. Except the ICH at second 1 is 0, not 1, because no one knows when your counter was zero: maybe it incremented right there, maybe it got incremented yesterday, and stayed at 1 since then. (This is the reason why you won't see an increase the first time a counter appears with a value of 1 -- because your code just created and incremented it.)

increase(counter[5s]) is exactly rate(counter[5s]) * 5 (and increase(counter[2s]) is exactly rate(counter[2s]) * 2).

Now what happens in the real world is that your samples are not collected exactly every second on the second and rule evaluation doesn't happen exactly on the second either. So if you have a bunch of samples that are (more or less) 1 second apart and you use Prometheus' rate(counter[1s]), you'll get no output. That's because what Prometheus does is it takes all the samples in the 1 second range [now() - 1s, now()] (which would be a single sample in the vast majority of cases), tries to compute a rate and fails.

If you query rate(counter[5s]) OTOH, Prometheus will pick all the samples in the range [now() - 5s, now] (5 samples, covering approximately 4 seconds on average, say [t1, v1], [t2, v2], [t3, v3], [t4, v4], [t5, v5]) and (assuming your counter doesn't reset within the interval) will return (v5 - v1) / (t5 - t1). I.e. it actually computes the rate of increase over ~4s rather than 5s.

increase(counter[5s]) will return (v5 - v1) / (t5 - t1) * 5, so the rate of increase over ~4 seconds, extrapolated to 5 seconds.

Due to the samples not being exactly spaced, both rate and increase will often return floating point values for integer counters (which makes obvious sense for rate, but not so much for increase).

2 of 3
50

Prometheus calculates rate(counter[d]) at timestamp t in the following way:

  1. It selects raw samples for the counter time series on the time range (t-d ... t]. Note that the t-d timestamp isn't included in the time range, while t timestamp is included in the time range. If the selected time range contains less than two raw samples, then Prometheus returns an empty value (a gap) at the timestamp t.
  2. Then it calculates the increase of the selected raw samples. Usually it is calculated as the difference between the last selected sample and the first selected sample. Calculations become slightly complicated if the counter was reset to zero during the selected time range. Let's skip this for the sake of clarity.
  3. Then the resulting increase can be extrapolated if timestamps for the first and/or the last raw samples are located too far from the bounds of the selected time range.
  4. Then the rate is calculated by dividing the extrapolated increase by d.

Prometheus calculates increase(counter[d]) in the same way except the last step.

Let's look at a few examples applied to the original data:

second   counter_value    increase calculated by hand(call it ICH from now)
1             1                    1
2             3                    2
3             6                    3
4             7                    1
5            10                    3
6            14                    4
7            17                    3
8            21                    4
9            25                    4
10           30                    5
  • The rate(counter[1s]) will return nothing at any timestamp t, since any time range (t-1s ... t] contains only a single raw sample, while Prometheus requires at least two samples for calculating both rate() and increase().

  • The rate(counter[2s]) and increase(counter[2]) would return the following values per each timestamp t when extrapolation isn't applied:

t       counter_value    rate(counter[2s])        increase(counter[2s])
1             1                    -                       -
2             3               (3-1)/2=1.0                3-1=2
3             6               (6-3)/2=1.5                6-3=3
4             7               (7-6)/2=0.5                7-6=1
5            10              (10-7)/2=1.5               10-7=3
6            14             (14-10)/2=2                14-10=4
7            17             (17-14)/2=1.5              17-14=3
8            21             (21-17)/2=2                21-17=4
9            25             (25-21)/2=2                25-21=4
10           30             (30-25)/2=2.5              30-25=5

In reality Prometheus results for rate(counter[2s]) and increase(counter[2s]) may be slightly bigger because of extrapolation, since the first sample on the selected time range is located comparatively far from the start of the time range.

Such calculations have the following issues:

  • Prometheus can return fractional results from increase() over time series, which contains only integer values. This is because of extrapolation. For example, Prometheus may return fractional results from increase(http_requests_total[5m]).

  • Prometheus returns empty results (aka gaps) from increase(counter[d]) and rate(counter[d]) when the lookbehind window d doesn't cover at least two samples - see rate(counter[1s]) and increase(counter[1s]) example above.

  • Prometheus completely misses the increase between the raw sample just before the (t-d ... t] interval and the first raw sample on this interval. This may result in inaccurate calculations. For example, increase(counter[1h]) doesn't equal to sum_over_time(increase(counter[1m])[1h:1m]).

Prometheus developers are aware of these issues - see this link. These issues are addressed in the system I work on - VictoriaMetrics - more specifically, in MetricsQL query language - see this comment and this article for technical details.

Discussions

How to deal with Increase function and no data points
The correct thing to do is to init your counters at startup. This avoids null results for rare counters. More on reddit.com
🌐 r/PrometheusMonitoring
5
6
September 3, 2021
solution: accurate `increase` function
There has been a frequent request for prometheus to implement an increase function that "just works" for the common situation of wanting to know the increase of a counter over time. The c... More on github.com
🌐 github.com
4
February 6, 2020
prometheus - Increase() vs changes() function for counters - Stack Overflow
I have a gift-certificates application that increases Prometheus counter whenever someone activates a certificate. Now I want to put simple number in Grafana board that shows me how many certificates More on stackoverflow.com
🌐 stackoverflow.com
Should I use PromQL's increase function as an alert rule expression for a resource quota breach?
See offset docs here: https://prometheus.io/docs/prometheus/latest/querying/basics/ I’m not sure if increase is reliable across long time windows like this, but it should handle resets in the counters, which the offset won’t handle. If you know that the metric is monotonic and never resets, then you could use the offset instead. Finally, you can take a look at recording rules, which allow to generate a new precalculated metric out of another metrics. More on reddit.com
🌐 r/PrometheusMonitoring
1
3
September 9, 2024
🌐
SigNoz
signoz.io › guides › what is the difference between prometheus rate vs increase functions
Prometheus rate vs increase Functions Explained | SigNoz
June 23, 2026 - Rate() calculates per-second average change; increase() shows total change over time. Both functions are essential for analyzing counter metrics in Prometheus.
🌐
OneUptime
oneuptime.com › home › blog › how to understand rate() vs increase() in prometheus
How to Understand rate() vs increase() in Prometheus
December 17, 2025 - Use increase() when you need absolute counts for totals, billing, and single-value displays. Both functions handle counter resets automatically, making them safe to use across service restarts.
🌐
Better Stack
betterstack.com › community › questions › do-i-understand-prometheus-rate-vs-increase-correctly
Do I Understand Prometheus's Rate Vs Increase Functions Correctly? | Better Stack Community
December 2, 2024 - Use increase when you need to know the total amount of something that occurred (e.g., total requests over a time period). ... Get notified with a radically better infrastructure monitoring platform.
🌐
Reddit
reddit.com › r/prometheusmonitoring › how to deal with increase function and no data points
r/PrometheusMonitoring on Reddit: How to deal with Increase function and no data points
September 3, 2021 -

I need to use the increase function, but the metric is very rare and when service restarts the counter is null for long time. The increase metric doesn’t play nicely with the null value and I can find a solution to consider null as zero.

Increase(my_counter[1h])

Works only if there are no null data points. Any other query I tried do not work like

Increase(my_metrics[1h] or vector(0))
🌐
PagerTree
pagertree.com › learn › prometheus › promeql › counter rates & increases
Counter Rates & Increases | PagerTree
increase() - "absolute increase" - calculates the absolute increase over a given time value, including extrapolation.
Find elsewhere
🌐
Medium
mohansaiteki.medium.com › manually-calculate-the-rate-irate-and-increase-functions-in-prometheus-7e755fff9897
Manually calculate the rate, irate, and increase functions in Prometheus
August 21, 2023 - The increase function is a simple function compared to others and it takes the starting and ending values in a given time range and calculates the difference. So you will get how much a value has increased in a given time range.
🌐
MetricFire
metricfire.com › blog › understanding-the-prometheus-rate-function
How the Prometheus rate() function works | MetricFire
March 12, 2026 - In Prometheus's query language, PromQL, the rate() function is used to determine the average per-second rate of increase of a counter metric over a given time range.
🌐
OneUptime
oneuptime.com › home › blog › how to calculate cumulative increase in prometheus
How to Calculate Cumulative Increase in Prometheus
December 17, 2025 - increase() automatically handles counter resets by detecting when a value drops and assuming it reset from zero. sequenceDiagram participant P as Prometheus participant M as Metric M->>P: Sample: 100 M->>P: Sample: 150 Note right of P: increase ...
🌐
GitHub
github.com › prometheus › prometheus › issues › 6779
solution: accurate `increase` function · Issue #6779 · prometheus/prometheus
February 6, 2020 - There has been a frequent request for prometheus to implement an increase function that "just works" for the common situation of wanting to know the increase of a counter over time. The current implementation misses increases at the begi...
Author: prometheus
🌐
GitConnected
levelup.gitconnected.com › prometheus-counter-metrics-d6c393d86076
Working With Prometheus Counter Metrics | Level Up Coding
February 28, 2022 - Prometheus’ increase function calculates the counter increase over a specified time frame². The following PromQL expression calculates the number of job executions over the past 5 minutes.
🌐
Last9
last9.io › blog › prometheus-rate-function
Prometheus Rate Function: A Practical Guide to Using It | Last9
June 15, 2026 - Last9 is a managed observability platform compatible with Prometheus and OpenTelemetry. Run PromQL against your metrics without operating Prometheus storage yourself. Try Last9 free. While rate() calculates the per-second average rate of increase, increase() calculates the total increase in the counter’s value over the time range.
🌐
DoiT
doit.com › home › blog › making peace with prometheus rate()
Making peace with Prometheus rate() | DoiT
February 17, 2023 - So basically Prometheus understands that the actual range in each bucket is one scrape less, i.e. 45 seconds instead of 60 in our case, so when it sees metric changed by 1 in a bucket, it’s actually “by 1 in 45 seconds”, not “by 1 in 60 seconds”, so it extrapolates the result as 1 / 45 * 60 = 1.33 and this is how we end up with increase() values being larger than the actual change.
🌐
Medium
pramodshehan.medium.com › prometheus-counter-metrics-1b0a4cbb79e1
Prometheus Counter metrics. There are three functions to calculate… | by Pramod Shehan | Medium
January 18, 2026 - rate(http_requests_total{job="api-server"}[5m]) increase(http_requests_total{job="api-server"}[5m]) irate(http_requests_total{job="api-server"}[5m]) Each of those functions take a range vector full of counter time series as an input and return ...
🌐
Promlabs
promlabs.com › blog › 2021 › 01 › 29 › how-exactly-does-promql-calculate-rates
PromLabs | Blog - How Exactly Does PromQL Calculate Rates?
January 29, 2021 - All three functions share the requirement that they need at least two samples under the provided range window to work. Series that have less than two samples under the window are simply dropped from the result. How exactly to calculate the increase given a fixed time window and some data points falling under that window is a matter of tradeoffs and imperfect approximations. Prometheus chooses an approach that aims to provide the most correct answer on average, given only the limited data under the provided window.
🌐
Last9
last9.io › blog › prometheus-functions
Prometheus Functions: How to Make the Most of Your Metrics | Last9
February 28, 2025 - These metrics form the foundation of monitoring and observability in Prometheus. Can I use range vectors in alerting rules? Yes, and you absolutely should! Range vectors are essential for creating meaningful, actionable alerts: ... Range vectors allow alerts based on trends, reducing noise from temporary spikes. Functions like rate(), increase(), and avg_over_time() combined with range vectors help predict problems before they become critical.
🌐
Google Groups
groups.google.com › g › prometheus-users › c › TfsMnT4E5kk
Issue with Prometheus increase()
October 6, 2022 - Now, when the counter gets increased due to some transactions, since the we don't have the time series data in the past the increase function return 0 even if the counter is at some x value.
🌐
Reddit
reddit.com › r/prometheusmonitoring › should i use promql's increase function as an alert rule expression for a resource quota breach?
r/PrometheusMonitoring on Reddit: Should I use PromQL's increase function as an alert rule expression for a resource quota breach?
September 9, 2024 -

I have this Prometheus alert expression which tries to capture if/when we exceed the monthly quota of a service by using the increase function on a counter metric over a 30day period.

sum(increase(external_requests_total{cacheHit="false", environment="prod", partner="partner_name"}[30d])) > 10000

I believe we should use a recording rule to somehow have a pre-calculated value to avoid crunching a month's worth of time-series data on each rules evaluation, but I also can't help but feel using a prometheus alert is not the right way to monitor this metric.

I'm open for suggestions on improving the rule or even a better alternative for this this kind of monitoring.