PromQL, short for Prometheus Query Language, is the functional query language built into Prometheus for selecting, filtering, and aggregating time-series metrics. Every dashboard panel, alerting rule, and recording rule in a Prometheus setup is ultimately a PromQL expression evaluated against the metrics the server has scraped.
The language reads more like a set of chained transformations than a traditional query. A user selects a metric by name and label, narrows it with a time window or filter, then applies a function to turn raw samples into a rate, an average, or a threshold check. That structure is what lets a single line answer a question like “what is the 95th percentile request latency for this service over the last five minutes.”
PromQL works with four data types, and understanding them is the fastest way to stop guessing at query errors.
Most PromQL mistakes trace back to mixing these types incorrectly, such as trying to graph a range vector directly instead of running it through a function like rate() first.
A PromQL query starts with a metric name, which by itself returns an instant vector of every time series carrying that name.
http_requests_total
Adding a label filter narrows that selection to specific series:
http_requests_total{job="api", status="500"}
Wrapping the metric in a range selector and a function turns raw counters into a meaningful rate:
rate(http_requests_total{status="500"}[5m])
That last query answers a specific operational question: how many 500 errors per second has this service produced, averaged over the last five minutes. Aggregation operators like sum by (job) can then roll that rate up across every instance of a service.
A small set of functions covers most day-to-day queries.
High-cardinality label sets are the most frequent source of slow or expensive PromQL queries. A query that groups by a label with thousands of unique values, such as a raw user ID, forces Prometheus to compute across an enormous number of series.
Counter resets are another common trap. Because rate() and increase() are designed to handle counter resets from process restarts, applying them to a gauge metric instead of a counter produces meaningless results.
PromQL also has no native way to join data across unrelated metrics the way a SQL join would. Correlating a metric with a log line or a trace span requires a platform that unifies those signal types outside of PromQL itself, since the language only operates on the metrics store it was built for.
No. PromQL is a functional language purpose-built for labeled time-series data, while SQL is a general-purpose language for relational tables. PromQL has no joins in the SQL sense and its entire model is built around metrics, labels, and time windows.
rate() returns the per-second average rate of increase over a time window, while increase() returns the total increase over that same window. increase() is effectively rate() multiplied by the number of seconds in the window.
The most common causes are a label filter that does not match any scraped series, a metric name typo, or a range vector selector used where the query expects an instant vector. Checking the raw metric with a plain selector before adding filters usually isolates the problem quickly.
No. PromQL only operates on the time-series metrics stored inside Prometheus. Correlating a PromQL result with logs or traces requires a separate observability layer that ingests all three signal types together.
A recording rule pre-computes a PromQL expression on a schedule and stores the result as a new time series. Teams use recording rules to speed up dashboards and alerts that would otherwise re-run an expensive query every time they load.