You can use the argument list of group_left to include extra labels from the right operand (parentheses and indents for clarity):

(
  max(consul_health_service_status{status="critical"}) 
  by (service_name,status,node) == 1
)
   + on(service_name,node) group_left(env)
(
   0 * consul_service_tags
)

The important part here is the operation + on(service_name,node) group_left(env):

  • the + is "abused" as a join operator (fine since 0 * consul_service_tags always has the value 0)
  • group_left(env) is the modifier that includes the extra label env from the right (consul_service_tags)
Answer from user2361830 on Stack Overflow
Top answer
1 of 3
76

You can use the argument list of group_left to include extra labels from the right operand (parentheses and indents for clarity):

(
  max(consul_health_service_status{status="critical"}) 
  by (service_name,status,node) == 1
)
   + on(service_name,node) group_left(env)
(
   0 * consul_service_tags
)

The important part here is the operation + on(service_name,node) group_left(env):

  • the + is "abused" as a join operator (fine since 0 * consul_service_tags always has the value 0)
  • group_left(env) is the modifier that includes the extra label env from the right (consul_service_tags)
2 of 3
15

It is a good practice in Prometheus ecosystem to expose additional labels, which can be joined to multiple metrics, via a separate info-like metric as explained in this article. For example, consul_service_tags metric exposes a set of tags, which can be joined to metrics via (service_name, node) labels.

The join is usually performed via on() and group_left() modifiers applied to * operation. The * doesn't modify values for time series on the left side because info-like metrics usually have constant 1 values. The on() modifier is used for limiting the labels used for finding matching time series on the left and the right side of *. The group_left() modifier is used for adding additional labels from time series on the right side of *. See these docs for details.

For example, the following PromQL query adds env label from consul_service_tags metric to consul_health_service_status metric with the same set of (service_name, node) labels:

consul_health_service_status
  * on(service_name, node) group_left(env)
consul_service_tags

Additional label filters can be added to consul_health_service_status if needed. For example, the following query returns only time series with status="critical" label:

consul_health_service_status{status="critical"}
  * on(service_name, node) group_left(env)
consul_service_tags
Discussions

Joining two metrics - PromQL - Prometheus Monitoring System
Hello Team, I have been trying to join two metrics, But whenever I add an operator, I get no data. Could someone help me figure it out? topk(5, stddev(container_memory_usage{k8s_cluster_name=“lab”}) by (k8s_container_name)) * on(k8s_node_name) group_left(support_level) k8s_cluster_metadata{} More on discuss.prometheus.io
🌐 discuss.prometheus.io
0
December 19, 2023
monitoring - Is there a way to do a "left outer join" like query in PromQL? - Stack Overflow
I am trying to use two metrics (that share some labels, including one that I can use as an UUID) that should describe the same entities, in order to create alerts/dashboard that will alert me one an More on stackoverflow.com
🌐 stackoverflow.com
simpler syntax for joins on labels with different names
Background When doing joins, I usually encounter cases where I want to join through a label that has different names on each side. For example, suppose I have: A container_fs_reads_total metric wit... More on github.com
🌐 github.com
8
October 10, 2024
PromQL: provide more efficient way to "join" metric in query
Proposal Use case. Why is this important? Currently, PromQL provide keyword group_left to join two metrics, for example job:memory_usage_percent{instance_name=~".*"} * on(instance_name) g... More on github.com
🌐 github.com
11
July 23, 2020
🌐
Robust Perception
robustperception.io › left-joins-in-promql
Left joins in PromQL – Robust Perception | Prometheus Monitoring Experts
December 30, 2019 - PromQL doesn't have a feature called "joins", however does have "vector matching" which is a similar idea.
🌐
Iximiuz
iximiuz.com › en › posts › prometheus-vector-matching
Prometheus Cheat Sheet - How to Join Multiple Metrics (Vector Matching)
November 30, 2021 - How to join metrics on matching labels? Vector matching: one-to-one, one-to-many and many-to-one, many-to-many. What on/ignoring clause is for? group_left and group_right explained. Logical/set operations explained.
🌐
SigNoz
signoz.io › guides › how can i 'join' two metrics in a prometheus query? - joining metrics in promql
How can I 'join' two metrics in a Prometheus query? - Joining Metrics in PromQL | SigNoz
July 24, 2024 - Practice and experimentation are ... inner and outer join operations. Instead, it uses vector matching with modifiers like group_left and group_right to achieve similar results....
🌐
Atatus
atatus.com › blog › how-to-join-two-metrics-in-prometheus
How to Join two metrics in Prometheus?
August 12, 2025 - Metric joining in Prometheus is a method of combining two or more metrics to build more complex and insightful queries. This is achieved using PromQL (Prometheus Query Language) to create queries that merge related metrics based on their labels, ...
🌐
Google Groups
groups.google.com › g › prometheus-users › c › qlHK7r1hQVs
Joining two metrics in promtheus and having all labels from both
March 6, 2023 - Thanks, The reason the metrics have the same name as the label is because in order to bring the value in from the SNMP exporter as a lablel, you have to set the type as DisplayString. As from what I have read, doing a 'join' would not allow you yo get the value of the metric in as a label value.
Find elsewhere
🌐
OneUptime
oneuptime.com › home › blog › how to join two metrics in prometheus query
How to Join Two Metrics in Prometheus Query
December 17, 2025 - Learn how to join two metrics in Prometheus using vector matching with on(), group_left(), and group_right(). This guide covers one-to-one, many-to-one, and many-to-many joins with practical examples. By @nawazdhandala • Dec 17, 2025 • Reading time · Prometheus PromQL Vector Matching Joins ...
🌐
Google Groups
groups.google.com › g › prometheus-users › c › po4YEDU5uWw
Promql JOIN many-to-many matching
October 6, 2021 - You can't do a many-to-many join. Even if you could it's unclear what the semantics would be.
🌐
InfluxData Documentation
docs.influxdata.com › flux › v0 › stdlib › internal › promql › join
promql.join() function | Flux Documentation
April 8, 2024 - promql.join() joins two streams of tables on the group key and _time column. See experimental.join.
🌐
GitHub
github.com › influxdata › flux › blob › master › stdlib › internal › promql › join.md
flux/stdlib/internal/promql/join.md at master · influxdata/flux
Defines the function that joins the rows of each table. The return value is an object which defines the output record structure. This function must preserve the table grouping. ... import "internal/promql" a = from(bucket: "my-bucket") |> ...
Author: influxdata
🌐
Coralogix
coralogix.com › home › promql tutorial: 5 tricks to become a prometheus god
PromQL Tutorial: Basic Concepts & Examples - Coralogix
June 3, 2025 - SQL fans will be familiar with joining tables to increase the breadth and power of queries. Likewise, PromQL lets you join metrics.
🌐
Prometheus
discuss.prometheus.io › promql
Joining two metrics - PromQL - Prometheus Monitoring System
December 19, 2023 - Hello Team, I have been trying to join two metrics, But whenever I add an operator, I get no data. Could someone help me figure it out? topk(5, stddev(container_memory_usage{k8s_cluster_name=“lab”}) by (k8s_container_…
🌐
Medium
valyala.medium.com › promql-tutorial-for-beginners-9ab455142085
PromQL tutorial for beginners and humans | by Aliaksandr Valialkin | Medium
September 15, 2023 - SELECT ts.metric_name_plus_tags, r.timestamps, r.values FROM ( (SELECT time_series_id, array_agg(timestamp ORDER BY timestamp) AS timestamps, array_agg(value ORDER BY timestamp) AS values FROM metrics WHERE time_series_id IN ( SELECT id FROM time_series WHERE metric_name = 'node_network_receive_bytes_total' ) GROUP BY time_series_id ) ) AS r JOIN time_series AS ts ON (r.time_series_id = ts.id) Easy, isn’t it? :) The SQL must be even more complex in order to be on par with the one-word PromQL query above, since it doesn’t take into account time ranges and down-sampling, which are automatically handled by /query_range API for PromQL with start, end and step args.
🌐
Wavefront
docs.wavefront.com › wavefront_prometheus.html
Using PromQL | VMware Aria Operations for Applications Documentation
This section shows an example for how 2 queries can be combined with joins in WQL and PromQL.
🌐
GitHub
github.com › prometheus › prometheus › issues › 15146
simpler syntax for joins on labels with different names · Issue #15146 · prometheus/prometheus
October 10, 2024 - Background When doing joins, I usually encounter cases where I want to join through a label that has different names on each side. For example, suppose I have: A container_fs_reads_total metric with a pod label A some_custom_pod_info met...
Author: prometheus
🌐
GitHub
github.com › prometheus › prometheus › issues › 7649
PromQL: provide more efficient way to "join" metric in query · Issue #7649 · prometheus/prometheus
July 23, 2020 - Proposal Use case. Why is this important? Currently, PromQL provide keyword group_left to join two metrics, for example job:memory_usage_percent{instance_name=~".*"} * on(instance_name) group_right(app) instance_app_relation{app="test.db...
Author: prometheus
🌐
GitHub
github.com › prometheus › prometheus › issues › 3094
Making joins simpler in PromQL · Issue #3094 · prometheus/prometheus
August 20, 2017 - At yesterday's dev summit, and as part of the discussion around prometheus/snmp_exporter#180 , @brian-brazil also suggested making joins easier to write. This issue is to document possible changes / enhancements to PromQL.
Author: prometheus