name: metricsql description: >- VictoriaMetrics MetricsQL query language as a PromQL superset: rollup extensions, behavioral differences from PromQL (rate/increase semantics, implicit conversions, auto-aligned subqueries), label manipulation, WITH templates, keep_metric_names modifier, multiple-or filters, and query API enhancements. Invoke whenever task involves any interaction with MetricsQL or VictoriaMetrics queries — writing, debugging, optimizing, migrating PromQL to VictoriaMetrics, or reviewing.
MetricsQL
VictoriaMetrics PromQL superset. Syntactically backwards-compatible; semantically different for a subset of queries.
Lead with the diffs — that's where users get burned. PromQL fundamentals live in the sibling promql skill; this covers
only what PromQL doesn't.
References
- Behavioral diffs from PromQL — [
${CLAUDE_SKILL_DIR}/references/behavioral-diffs.md]rate/increase/delta/changesdiffs,_prometheus-suffixed variants, scalar/instant-vector unification, NaN handling, name retention, implicit conversions, auto-aligned subqueries,default_rolluplookback, staleness markers. - MetricsQL-only extensions — [
${CLAUDE_SKILL_DIR}/references/extensions.md] Rollup family,WITHtemplates, multiple-orfilters,default/if/ifnotops,group_left(*) prefix,keep_metric_names,[Ni]step, numeric suffixes, aggregatelimit N,boundsLabel, fractional durations, Graphite, multi-line. - Full function catalog — [
${CLAUDE_SKILL_DIR}/references/functions-catalog.md] All rollup, transform, label-manipulation, aggregate functions by category, with PromQL/MetricsQL provenance. - Query API enhancements — [
${CLAUDE_SKILL_DIR}/references/api-enhancements.md]extra_label,extra_filters[],round_digits,limit, timestamp formats,statsresponse, cluster vmselect URL layout, multi-tenancy.
Read the relevant reference before proceeding.
What MetricsQL Is
- Strict syntactic superset of PromQL — every valid PromQL parses as MetricsQL.
- Not semantic superset —
rate,increase,delta,changesdiffer. _prometheus-suffixed variants give byte-parity:rate_prometheus,increase_prometheus,delta_prometheus,changes_prometheus.- Implemented by
vmselect(cluster) or single-node binary; exposed via standard/api/v1/queryand/api/v1/query_range.
The Five Behavioral Diffs That Bite
- Lookbehind anchor.
rate/increaseuse the last sample before the window for the first delta; Prometheus doesn't. Forincrease(metric[$__interval])on a slow counter, Prometheus loses one delta per window. Userate_prometheus/increase_prometheusfor parity. - No extrapolation. Returns actual measured delta; Prometheus extrapolates to window edges, producing fractional
results from integer counters. Affects alerts comparing
increase()to integer thresholds. - Scalar = instant vector without labels. Prometheus's scalar/instant-vector distinction collapses.
scalar(metric)coercion rarely needed; arithmetic on aggregation results works. - NaN drop.
(-1)^0.5returns empty in MetricsQL; Prometheus returns a NaN series. Grafana renders identically; programmatic consumers see different shapes. - Metric names retained for safe functions.
min_over_time(foo),round(foo),abs(foo)keepfoo. Prometheus strips.
Full mechanics, edge cases, implicit-conversion pipeline, per-function table:
[${CLAUDE_SKILL_DIR}/references/behavioral-diffs.md].
Lookbehind Window — Auto-Selection
Omitting [d] is allowed:
default_rollupandrate:max(step, scrape_interval)— prevents gaps whenstep < scrape_interval.- All other rollups:
step($__intervalin Grafana,1i). rate(node_network_receive_bytes_total)≡rate(node_network_receive_bytes_total[$__interval]).
Silent behavior change across panels with different steps. For alerting and recording rules, always specify the window explicitly.
Implicit Query Conversions
VictoriaMetrics rewrites every query before evaluation (unless -search.disableImplicitConversion):
- Bare selectors →
default_rollup:foo→default_rollup(foo). - Selectors inside transform/aggregate get the same wrap:
abs(temperature)→abs(default_rollup(temperature)),count(up)→count(default_rollup(up)). - Rollups on non-selectors become subqueries:
rate(sum(up))→rate((sum(default_rollup(up)))[1i:1i]). - Subqueries with missing step get
1i:avg_over_time(rate(m[5m])[1h])→avg_over_time(rate(m[5m])[1h:1i]).
When debugging, mentally apply these first — the actual computation may differ from what was typed.
Full conversion list with disable flags: [${CLAUDE_SKILL_DIR}/references/behavioral-diffs.md].
The Rollup Family — MetricsQL-Only
rollup(m[d])— min/max/avg withrollup="..."label.rollup_rate(m[d])— per-second rate min/max/avg over adjacent samples; better thaniratefor spike detection.rollup_increase(m[d])/rollup_delta(m[d])/rollup_deriv(m[d])— same pattern.rollup_candlestick(m[d])— OHLC.aggr_over_time(("func1","func2",...), m[d])— multiple rollups in one pass.
Pair with keep_metric_names to preserve the original name.
keep_metric_names
Functions and binary ops strip the metric name. This causes duplicate time series errors when distinct names collapse
into the same label set. Suffix with keep_metric_names:
rate({__name__=~"foo|bar"}) keep_metric_names({__name__=~"foo|bar"} / 10) keep_metric_names
Available on all rollups, transforms, and binary operators.
Multiple or in Series Selectors
PromQL {env="prod",job="a"} is a single AND. MetricsQL adds top-level disjunction:
{env="prod",job="a" or env="dev",job="b"}
Each or-group is an AND of matchers. Compose with comma within a group.
Multi-constant matching: status_code == (300, 301, 304) returns series where status_code is any listed value.
WITH Templates
Reusable named subexpressions:
WITH (
errs = rate(http_requests_total{status=~"5.."}[5m]),
total = rate(http_requests_total[5m]),
)
sum(errs) by (job) / sum(total) by (job)
String concat: WITH (commonPrefix="my_app_") {__name__=commonPrefix+"errors_total"}. Expanded at parse time.
Binary Operators Beyond PromQL
q1 default q2— fills gaps inq1fromq2.q1 if q2— keepsq1whereq2has a value (conditional masking).q1 ifnot q2— keepsq1whereq2has no value (inverse).
Compose with default-on-missing: (up{job="x"} default 0) == 0 reliably alerts on disappearing targets.
group_left(*) and Label Copy
kube_pod_info * on(namespace) group_left(*) prefix "ns_" kube_namespace_labels
Copies all labels from right side except those in on(...), prefixed with ns_. group_right(*) mirrors. Without
prefix, collisions error.
Aggregate limit N
sum(http_requests_total) by (path) limit 10
Returns 10 paths total. Other series dropped silently. Distinct from topk(10, ...): limit N is order-arbitrary;
topk keeps the top by value.
Grafana $__interval and [Ni] Syntax
1i= one step (Grafanasteparg).[10i]= lookbehind covering ten steps.offset 5i= shift back five steps.- Works in rollup windows, offsets, subquery step:
rate(metric[10i] offset 5i). - Use over hard-coded durations so panels scale with the time range.
Cluster Endpoint Structure
http://<vmselect>:8481/select/<accountID>/prometheus/api/v1/query
http://<vmselect>:8481/select/<accountID>/prometheus/api/v1/query_range
<accountID> is accountID or accountID:projectID (32-bit ints). Single-node uses unprefixed /api/v1/query.
/prometheus/ prefix is optional but explicit.
Full URL layout (ingestion, federation, Graphite, vmstorage admin, vmalert proxy):
[${CLAUDE_SKILL_DIR}/references/api-enhancements.md].
Query API Enhancements
extra_label=<name>=<value>— adds{name="value"}to every selector. Repeatable. Used by auth proxies for tenant scoping.extra_filters[]=<selector>— adds a full selector with regex support:extra_filters[]={env=~"prod|staging"}.round_digits=N— rounds response values to N decimals.limit=Non/api/v1/labels,/api/v1/label/<name>/values,/api/v1/series.
Responses include stats with executionTimeMsec and seriesFetched. seriesFetched is approximate; vmalert uses it
to flag never-firing rules.
Syntax Conveniences
- Underscore in numbers —
1_234_567_890≡1234567890 - Numeric suffixes —
8K(8000),1.2Mi(1.2×1024²), supportsK Ki M Mi G Gi T Ti - Fractional durations —
[1.5m],offset 0.5d - Optional duration suffix —
[300]is seconds:rate(m[300] offset 1800)≡rate(m[5m]) offset 30m - Duration anywhere —
sum_over_time(m[1h]) / 1h≡sum_over_time(m[1h]) / 3600 - Trailing commas —
m{foo="bar",},f(a, b,),WITH (x=y,) xall valid. Use in multi-line queries. - Unicode in names —
ტემპერატურა{πόλη="Київ"}is valid - Escape sequences —
foo\-bar{baz\=aa="b"},\xXX,\uXXXX @ modifieranywhere —sum(foo) @ end(),foo @ (end() - 1h)
Histogram Extensions
histogram_quantile(phi, buckets, boundsLabel?) — optional third arg returns lower/upper bounds in boundsLabel.
For plotting quantile confidence intervals.
histogram_over_time(gauge[d]) produces VictoriaMetrics-format histograms from gauge values:
histogram_quantile(0.5, sum(histogram_over_time(temperature[24h])) by (vmrange,country))
Computes quantiles over gauge distributions without re-instrumenting.
Application
When writing:
- Omit lookbehind only when panel-wide
$__intervalis appropriate. Otherwise use[5m]or[Ni]explicitly. - For alerting/recording rules: always specify the lookbehind window. Implicit selection couples rule behavior to evaluation interval.
- Prefer
defaultoveror vector(0)— more readable, handles labels correctly. - Use
rollup_ratefor counter spike detection overirate— min/max/avg in one query.
When migrating from Prometheus:
- Audit alerts comparing
increase()to integer thresholds — exact integers may fire differently. - Use
*_prometheusvariants only when byte-parity is required (cross-backend SLO consistency). - Enable
-search.logImplicitConversionto see rewrites.
When reviewing:
- Flag missing lookbehind windows in alerting/recording rules.
- Flag
rate(sum(...))— silent subquery formation. - Flag bare selectors in arithmetic — silent
default_rollupwrap. - Cite the specific diff and show the fix inline.
Integration
promql — shared fundamentals (selectors, operators, aggregations, vector matching). This skill — MetricsQL extensions and diffs.
prometheus — instrumentation; this skill — query-time behavior.