From 352e36a7601cd720254d1a40d3cc07babce0cc82 Mon Sep 17 00:00:00 2001
From: Julien Pivotto <291750+roidelapluie@users.noreply.github.com>
Date: Mon, 29 Jun 2026 14:18:15 +0200
Subject: [PATCH] promql: enable duration expressions by default
Duration expressions no longer require the promql-duration-expr feature
flag, which is now a no-op in both prometheus and promtool. The parser
option (ExperimentalDurationExpr) is kept and enabled by default in the
binaries, so downstream consumers of the parser can still keep it off.
Move the documentation from the feature flags page into the PromQL
querying basics.
Signed-off-by: Julien Pivotto <291750+roidelapluie@users.noreply.github.com>
---
cmd/prometheus/main.go | 8 ++-
cmd/prometheus/testdata/features.json | 2 +-
cmd/promtool/main.go | 10 ++--
cmd/promtool/main_test.go | 2 +-
docs/command-line/prometheus.md | 2 +-
docs/command-line/promtool.md | 2 +-
docs/feature_flags.md | 60 -------------------
docs/querying/basics.md | 59 ++++++++++++++++++
docs/querying/functions.md | 3 +-
web/ui/mantine-ui/src/promql/functionDocs.tsx | 48 +++++----------
10 files changed, 91 insertions(+), 105 deletions(-)
diff --git a/cmd/prometheus/main.go b/cmd/prometheus/main.go
index 6795c6bb4c..7ad72270e7 100644
--- a/cmd/prometheus/main.go
+++ b/cmd/prometheus/main.go
@@ -261,8 +261,7 @@ func (c *flagConfig) setFeatureListOptions(logger *slog.Logger) error {
c.parserOpts.EnableExperimentalFunctions = true
logger.Info("Experimental PromQL functions enabled.")
case "promql-duration-expr":
- c.parserOpts.ExperimentalDurationExpr = true
- logger.Info("Experimental duration expression parsing enabled.")
+ logger.Warn("This option for --enable-feature is now permanently enabled and therefore a no-op.", "option", o)
case "native-histograms":
logger.Warn("This option for --enable-feature is a no-op. To scrape native histograms, set the scrape_native_histograms scrape config setting to true.", "option", o)
case "ooo-native-histograms":
@@ -391,6 +390,9 @@ func main() {
FeatureRegistry: features.DefaultRegistry,
},
promslogConfig: promslog.Config{},
+ // Duration expressions are enabled by default; the promql-duration-expr
+ // feature flag is now a no-op.
+ parserOpts: parser.Options{ExperimentalDurationExpr: true},
scrape: scrape.Options{
FeatureRegistry: features.DefaultRegistry,
},
@@ -636,7 +638,7 @@ func main() {
a.Flag("scrape.discovery-reload-interval", "Interval used by scrape manager to throttle target groups updates.").
Hidden().Default("5s").SetValue(&cfg.scrape.DiscoveryReloadInterval)
- a.Flag("enable-feature", "Comma separated feature names to enable. Valid options: concurrent-rule-eval, created-timestamp-zero-ingestion, delayed-compaction, exemplar-storage, extra-scrape-metrics, memory-snapshot-on-shutdown, metadata-wal-records, old-ui, otlp-deltatocumulative, otlp-native-delta-ingestion, promql-binop-fill-modifiers, promql-delayed-name-removal, promql-duration-expr, promql-experimental-functions, promql-extended-range-selectors, promql-per-step-stats, search-api, st-storage, st-synthesis, type-and-unit-labels, use-start-timestamps, use-uncached-io, xor2-encoding. See https://prometheus.io/docs/prometheus/latest/feature_flags/ for more details.").
+ a.Flag("enable-feature", "Comma separated feature names to enable. Valid options: concurrent-rule-eval, created-timestamp-zero-ingestion, delayed-compaction, exemplar-storage, extra-scrape-metrics, memory-snapshot-on-shutdown, metadata-wal-records, old-ui, otlp-deltatocumulative, otlp-native-delta-ingestion, promql-binop-fill-modifiers, promql-delayed-name-removal, promql-experimental-functions, promql-extended-range-selectors, promql-per-step-stats, search-api, st-storage, st-synthesis, type-and-unit-labels, use-start-timestamps, use-uncached-io, xor2-encoding. See https://prometheus.io/docs/prometheus/latest/feature_flags/ for more details.").
StringsVar(&cfg.featureList)
a.Flag("agent", "Run Prometheus in 'Agent mode'.").BoolVar(&agentMode)
diff --git a/cmd/prometheus/testdata/features.json b/cmd/prometheus/testdata/features.json
index 1cfce7709c..c49a5f43c1 100644
--- a/cmd/prometheus/testdata/features.json
+++ b/cmd/prometheus/testdata/features.json
@@ -32,7 +32,7 @@
"bool": true,
"by": true,
"delayed_name_removal": false,
- "duration_expr": false,
+ "duration_expr": true,
"fill": false,
"fill_left": false,
"fill_right": false,
diff --git a/cmd/promtool/main.go b/cmd/promtool/main.go
index a6dd4e0c05..385e8077d7 100644
--- a/cmd/promtool/main.go
+++ b/cmd/promtool/main.go
@@ -64,8 +64,10 @@ import (
var (
promqlEnableDelayedNameRemoval = false
- promtoolParserOpts parser.Options
- logger = promslog.New(&promslog.Config{})
+ // Duration expressions are enabled by default; the promql-duration-expr
+ // feature flag is now a no-op.
+ promtoolParserOpts = parser.Options{ExperimentalDurationExpr: true}
+ logger = promslog.New(&promslog.Config{})
)
func init() {
@@ -320,7 +322,7 @@ func main() {
promQLLabelsDeleteQuery := promQLLabelsDeleteCmd.Arg("query", "PromQL query.").Required().String()
promQLLabelsDeleteName := promQLLabelsDeleteCmd.Arg("name", "Name of the label to delete.").Required().String()
- featureList := app.Flag("enable-feature", "Comma separated feature names to enable. Valid options: promql-experimental-functions, promql-delayed-name-removal, promql-duration-expr, promql-extended-range-selectors. See https://prometheus.io/docs/prometheus/latest/feature_flags/ for more details").Default("").Strings()
+ featureList := app.Flag("enable-feature", "Comma separated feature names to enable. Valid options: promql-experimental-functions, promql-delayed-name-removal, promql-extended-range-selectors. See https://prometheus.io/docs/prometheus/latest/feature_flags/ for more details").Default("").Strings()
documentationCmd := app.Command("write-documentation", "Generate command line documentation. Internal use.").Hidden()
@@ -358,7 +360,7 @@ func main() {
case "promql-delayed-name-removal":
promqlEnableDelayedNameRemoval = true
case "promql-duration-expr":
- promtoolParserOpts.ExperimentalDurationExpr = true
+ // This feature is now permanently enabled and therefore a no-op.
case "promql-extended-range-selectors":
promtoolParserOpts.EnableExtendedRangeSelectors = true
case "":
diff --git a/cmd/promtool/main_test.go b/cmd/promtool/main_test.go
index e42ca69441..7a15cf1c0b 100644
--- a/cmd/promtool/main_test.go
+++ b/cmd/promtool/main_test.go
@@ -702,7 +702,7 @@ func TestCheckRulesWithFeatureFlag(t *testing.T) {
// As opposed to TestCheckRules calling CheckRules directly we run promtool
// so the feature flag parsing can be tested.
- args := []string{"-test.main", "--enable-feature=promql-experimental-functions", "--enable-feature=promql-duration-expr", "--enable-feature=promql-extended-range-selectors", "check", "rules", "testdata/features.yml"}
+ args := []string{"-test.main", "--enable-feature=promql-experimental-functions", "--enable-feature=promql-extended-range-selectors", "check", "rules", "testdata/features.yml"}
tool := exec.Command(promtoolPath, args...)
err := tool.Run()
require.NoError(t, err)
diff --git a/docs/command-line/prometheus.md b/docs/command-line/prometheus.md
index 5ec738e768..a9f6d033ba 100644
--- a/docs/command-line/prometheus.md
+++ b/docs/command-line/prometheus.md
@@ -63,7 +63,7 @@ The Prometheus monitoring server
| --query.timeout | Maximum time a query may take before being aborted. Use with server mode only. | `2m` |
| --query.max-concurrency | Maximum number of queries executed concurrently. Use with server mode only. | `20` |
| --query.max-samples | Maximum number of samples a single query can load into memory. Note that queries will fail if they try to load more samples than this into memory, so this also limits the number of samples a query can return. Use with server mode only. | `50000000` |
-| --enable-feature ... | Comma separated feature names to enable. Valid options: concurrent-rule-eval, created-timestamp-zero-ingestion, delayed-compaction, exemplar-storage, extra-scrape-metrics, memory-snapshot-on-shutdown, metadata-wal-records, old-ui, otlp-deltatocumulative, otlp-native-delta-ingestion, promql-binop-fill-modifiers, promql-delayed-name-removal, promql-duration-expr, promql-experimental-functions, promql-extended-range-selectors, promql-per-step-stats, search-api, st-storage, st-synthesis, type-and-unit-labels, use-start-timestamps, use-uncached-io, xor2-encoding. See https://prometheus.io/docs/prometheus/latest/feature_flags/ for more details. | |
+| --enable-feature ... | Comma separated feature names to enable. Valid options: concurrent-rule-eval, created-timestamp-zero-ingestion, delayed-compaction, exemplar-storage, extra-scrape-metrics, memory-snapshot-on-shutdown, metadata-wal-records, old-ui, otlp-deltatocumulative, otlp-native-delta-ingestion, promql-binop-fill-modifiers, promql-delayed-name-removal, promql-experimental-functions, promql-extended-range-selectors, promql-per-step-stats, search-api, st-storage, st-synthesis, type-and-unit-labels, use-start-timestamps, use-uncached-io, xor2-encoding. See https://prometheus.io/docs/prometheus/latest/feature_flags/ for more details. | |
| --agent | Run Prometheus in 'Agent mode'. | |
| --log.level | Only log messages with the given severity or above. One of: [debug, info, warn, error] | `info` |
| --log.format | Output format of log messages. One of: [logfmt, json] | `logfmt` |
diff --git a/docs/command-line/promtool.md b/docs/command-line/promtool.md
index 06c6f87874..dc9e3074ce 100644
--- a/docs/command-line/promtool.md
+++ b/docs/command-line/promtool.md
@@ -12,7 +12,7 @@ Tooling for the Prometheus monitoring system.
| -h, --help | Show context-sensitive help (also try --help-long and --help-man). |
| --version | Show application version. |
| --experimental | Enable experimental commands. |
-| --enable-feature ... | Comma separated feature names to enable. Valid options: promql-experimental-functions, promql-delayed-name-removal, promql-duration-expr, promql-extended-range-selectors. See https://prometheus.io/docs/prometheus/latest/feature_flags/ for more details |
+| --enable-feature ... | Comma separated feature names to enable. Valid options: promql-experimental-functions, promql-delayed-name-removal, promql-extended-range-selectors. See https://prometheus.io/docs/prometheus/latest/feature_flags/ for more details |
diff --git a/docs/feature_flags.md b/docs/feature_flags.md
index 8b500dba50..cd83ab91d6 100644
--- a/docs/feature_flags.md
+++ b/docs/feature_flags.md
@@ -214,66 +214,6 @@ state is mutex guarded. Cumulative-only OTLP requests are not affected.
[d2c]: https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/processor/deltatocumulativeprocessor
-## PromQL arithmetic expressions in time durations
-
-`--enable-feature=promql-duration-expr`
-
-With this flag, arithmetic expressions can be used in time durations in range queries and offset durations.
-
-In range queries:
-```
-rate(http_requests_total[5m * 2]) # 10 minute range
-rate(http_requests_total[(5+2) * 1m]) # 7 minute range
-```
-
-In offset durations:
-```
-http_requests_total offset (1h / 2) # 30 minute offset
-http_requests_total offset ((2 ^ 3) * 1m) # 8 minute offset
-```
-
-When using offset with duration expressions, you must wrap the expression in
-parentheses. Without parentheses, only the first duration value will be used in
-the offset calculation.
-
-`step()` can be used in duration expressions.
-For a **range query**, it resolves to the step width of the range query.
-For an **instant query**, it resolves to `0s`.
-
-`range()` can be used in duration expressions.
-For a **range query**, it resolves to the full range of the query (end time - start time).
-For an **instant query**, it resolves to `0s`.
-This is particularly useful in combination with `@end()` to look back over the entire query range, e.g., `max_over_time(metric[range()] @ end())`.
-
-`min_of(m within the 1m range, where m offset 1m will select the most
recent sample within the lookback interval outside and prior to the 1m offset. This is particularly
useful with first_over_time(m[step()])
- in range queries (available when --enable-feature=promql-duration-expr is set) to ensure that the
- sample selected is within the range step.
+ in range queries to ensure that the sample selected is within the range step.
m within the 1m range, where m offset 1m will select the most
recent sample within the lookback interval outside and prior to the 1m offset. This is particularly
useful with first_over_time(m[step()])
- in range queries (available when --enable-feature=promql-duration-expr is set) to ensure that the
- sample selected is within the range step.
+ in range queries to ensure that the sample selected is within the range step.
>
),
@@ -1240,8 +1238,7 @@ const funcDocs: Recordm within the 1m range, where m offset 1m will select the most
recent sample within the lookback interval outside and prior to the 1m offset. This is particularly
useful with first_over_time(m[step()])
- in range queries (available when --enable-feature=promql-duration-expr is set) to ensure that the
- sample selected is within the range step.
+ in range queries to ensure that the sample selected is within the range step.
>
),
@@ -2072,8 +2069,7 @@ const funcDocs: Recordm within the 1m range, where m offset 1m will select the most
recent sample within the lookback interval outside and prior to the 1m offset. This is particularly
useful with first_over_time(m[step()])
- in range queries (available when --enable-feature=promql-duration-expr is set) to ensure that the
- sample selected is within the range step.
+ in range queries to ensure that the sample selected is within the range step.
>
),
@@ -2223,8 +2219,7 @@ const funcDocs: Recordm within the 1m range, where m offset 1m will select the most
recent sample within the lookback interval outside and prior to the 1m offset. This is particularly
useful with first_over_time(m[step()])
- in range queries (available when --enable-feature=promql-duration-expr is set) to ensure that the
- sample selected is within the range step.
+ in range queries to ensure that the sample selected is within the range step.
>
),
@@ -2349,8 +2344,7 @@ const funcDocs: Recordm within the 1m range, where m offset 1m will select the most
recent sample within the lookback interval outside and prior to the 1m offset. This is particularly
useful with first_over_time(m[step()])
- in range queries (available when --enable-feature=promql-duration-expr is set) to ensure that the
- sample selected is within the range step.
+ in range queries to ensure that the sample selected is within the range step.
>
),
@@ -2475,8 +2469,7 @@ const funcDocs: Recordm within the 1m range, where m offset 1m will select the most
recent sample within the lookback interval outside and prior to the 1m offset. This is particularly
useful with first_over_time(m[step()])
- in range queries (available when --enable-feature=promql-duration-expr is set) to ensure that the
- sample selected is within the range step.
+ in range queries to ensure that the sample selected is within the range step.
>
),
@@ -2691,8 +2684,7 @@ const funcDocs: Recordm within the 1m range, where m offset 1m will select the most
recent sample within the lookback interval outside and prior to the 1m offset. This is particularly
useful with first_over_time(m[step()])
- in range queries (available when --enable-feature=promql-duration-expr is set) to ensure that the
- sample selected is within the range step.
+ in range queries to ensure that the sample selected is within the range step.
>
),
@@ -2801,8 +2793,7 @@ const funcDocs: Recordm within the 1m range, where m offset 1m will select the most
recent sample within the lookback interval outside and prior to the 1m offset. This is particularly
useful with first_over_time(m[step()])
- in range queries (available when --enable-feature=promql-duration-expr is set) to ensure that the
- sample selected is within the range step.
+ in range queries to ensure that the sample selected is within the range step.
>
),
@@ -3315,8 +3306,7 @@ const funcDocs: Recordm within the 1m range, where m offset 1m will select the most
recent sample within the lookback interval outside and prior to the 1m offset. This is particularly
useful with first_over_time(m[step()])
- in range queries (available when --enable-feature=promql-duration-expr is set) to ensure that the
- sample selected is within the range step.
+ in range queries to ensure that the sample selected is within the range step.
>
),
@@ -3425,8 +3415,7 @@ const funcDocs: Recordm within the 1m range, where m offset 1m will select the most
recent sample within the lookback interval outside and prior to the 1m offset. This is particularly
useful with first_over_time(m[step()])
- in range queries (available when --enable-feature=promql-duration-expr is set) to ensure that the
- sample selected is within the range step.
+ in range queries to ensure that the sample selected is within the range step.
>
),
@@ -3551,8 +3540,7 @@ const funcDocs: Recordm within the 1m range, where m offset 1m will select the most
recent sample within the lookback interval outside and prior to the 1m offset. This is particularly
useful with first_over_time(m[step()])
- in range queries (available when --enable-feature=promql-duration-expr is set) to ensure that the
- sample selected is within the range step.
+ in range queries to ensure that the sample selected is within the range step.
>
),
@@ -3817,8 +3805,7 @@ const funcDocs: Recordm within the 1m range, where m offset 1m will select the most
recent sample within the lookback interval outside and prior to the 1m offset. This is particularly
useful with first_over_time(m[step()])
- in range queries (available when --enable-feature=promql-duration-expr is set) to ensure that the
- sample selected is within the range step.
+ in range queries to ensure that the sample selected is within the range step.
>
),
@@ -3927,8 +3914,7 @@ const funcDocs: Recordm within the 1m range, where m offset 1m will select the most
recent sample within the lookback interval outside and prior to the 1m offset. This is particularly
useful with first_over_time(m[step()])
- in range queries (available when --enable-feature=promql-duration-expr is set) to ensure that the
- sample selected is within the range step.
+ in range queries to ensure that the sample selected is within the range step.
>
),
@@ -4037,8 +4023,7 @@ const funcDocs: Recordm within the 1m range, where m offset 1m will select the most
recent sample within the lookback interval outside and prior to the 1m offset. This is particularly
useful with first_over_time(m[step()])
- in range queries (available when --enable-feature=promql-duration-expr is set) to ensure that the
- sample selected is within the range step.
+ in range queries to ensure that the sample selected is within the range step.
>
),
@@ -4147,8 +4132,7 @@ const funcDocs: Recordm within the 1m range, where m offset 1m will select the most
recent sample within the lookback interval outside and prior to the 1m offset. This is particularly
useful with first_over_time(m[step()])
- in range queries (available when --enable-feature=promql-duration-expr is set) to ensure that the
- sample selected is within the range step.
+ in range queries to ensure that the sample selected is within the range step.
>
),