DevTools Logo
All posts

A Practical PromQL Guide: Selectors, Rates, and Aggregations

August 10, 2026 · DevTools

promql
prometheus
monitoring
grafana
query-language

Every PromQL query is three ideas stacked together: a metric selector, an optional range function, and an optional aggregation. Once you see that shape, the syntax stops being the hard part.

A selector is the metric name plus label matchers — http_requests_total{job="api", status=~"5.."}. The four operators are = (equals), != (not equals), =~ (regex matches), and !~ (regex does not match), and PromQL is forgiving of an empty matcher set: http_requests_total matches all series.

Counter metrics need a range function before they mean anything on a chart. rate(http_requests_total[5m]) converts a counter into a per-second average over the window, smoothing out resets; increase(...[5m]) reports the total growth over that window instead. Gauge-derived calculations skip this step.

Aggregations collapse a set of time series into one. sum by (status) (rate(http_requests_total[5m])) buckets the request rate per status code, while topk(5, ...) keeps only the five busiest series. Remember the order: selector first, range function next, aggregation outermost.

Two mistakes break most hand-written queries: applying rate to an instant vector (the window is what makes it a range vector), and aggregating without a by clause to keep your labels. When you are assembling one yourself, the PromQL Query Builder composes the same steps from a form — try it alongside Prometheus's own querying documentation to confirm what each part produces.

Tools mentioned in this post