I think the keyword in that comment is shareable or in other words reusable rules. Meaning you (often) preserve more labels while using ignoring compared to on and the results will be (usually) a rule with more of it's original labels left intact, so it can be reused for more scenarios.

Imagine these time series:

instance_cpu_time_ns{app="lion", proc="web", rev="34d0f99", env="prod", job="cluster-manager"}
instance_cpu_time_ns{app="elephant", proc="worker", rev="34d0f99", env="prod", job="cluster-manager"}
instance_cpu_time_ns{app="turtle", proc="api", rev="4d3a513", env="prod", job="cluster-manager"}
instance_cpu_time_ns{app="fox", proc="widget", rev="4d3a513", env="prod", job="cluster-manager"}
...

A query with ignoring(rev) leaves out all the other labels in the result, compared with the same query with on(app).

But the result of on and ignoring would be identical if you use them with mutually exclusive set of labels, like the example you are mentioning.

Answer from Ali Sattari on serverfault.com
🌐
Prometheus
prometheus.io › docs › prometheus › latest › querying › operators
Operators | Prometheus
Many-to-one and one-to-many matchings refer to the case where each vector element on the "one"-side can match with multiple elements on the "many"-side. This has to be explicitly requested using the group_left or group_right modifiers, where left/right determines which vector has the higher cardinality.
🌐
Robust Perception
robustperception.io › using-group_left-to-calculate-label-proportions
Using group_left to calculate label proportions – Robust Perception | Prometheus Monitoring Experts
When you've broken a metric out into labels a common need is to tell what proportion each label represents of the total. The group_left modifier of Prometheus is the key.
Discussions

monitoring - How can I 'join' two metrics in a Prometheus query? - Stack Overflow
iximiuz.com/en/posts/prometheus-vector-matching ... Save this answer. ... Show activity on this post. You can use the argument list of group_left to include extra labels from the right operand (parentheses and indents for clarity): More on stackoverflow.com
🌐 stackoverflow.com
promql - join prometheus queries while keeping data from the left side - Stack Overflow
I want to build promql query that joins two vectors: one with some metrics and other is informational. The caveat is that info vector doesn't have all the information for "joining label",... More on stackoverflow.com
🌐 stackoverflow.com
Error when using group_left in Prometheus - Stack Overflow
The group_left() modifier expects that the right-hand side of * operator (and any other operator) contains only a single time series per each label=value set specified inside on() modifier. Otherwise it returns duplicate series for the match group error. More on stackoverflow.com
🌐 stackoverflow.com
Prometheus add extra label on join request without using group statement? - Stack Overflow
If you need retaining only some labels from the left side, then just drop unneeded labels after the calculations of q1 * on (...) group_left() q2. Prometheus doesn't provide functions, which can drop unneeded labels from time series (or leave only the needed labels), but this functionality ... More on stackoverflow.com
🌐 stackoverflow.com
🌐
Webscale
webscale.com › home › blog › prometheus querying – breaking down promql
PromQL Querying: group_left, Joins, and Working Examples
June 8, 2026 - varnish_main_client_req{namespace="section-9469f9cc28d8d"} * on (pod) group_left(node) kube_pod_info ... We can then take this over to Grafana to make a dashboard and chart, add this data to a graph panel, and clearly view it all. Sometimes graphing a query might overload the server or browser, or lead to a time out because the amount of data is too large. When constructing queries over unknown data, it is better to begin building the query in the tabular view of Prometheus’ expression browser until you arrive at a reasonable result set (i.e.
🌐
Chris's Wiki
utcc.utoronto.ca › ~cks › space › blog › sysadmin › PrometheusGroupLeftAndRightNotes
Prometheus's group_left() and group_right() operators
December 17, 2023 - The value comes from the left side ... to one match, this is why you want to use group_left() instead of group_right(); it automatically preserves all of the labels of your left side metric.)...
🌐
Iximiuz
iximiuz.com › en › posts › prometheus-vector-matching
Prometheus Cheat Sheet - How to Join Multiple Metrics (Vector Matching)
November 30, 2021 - If the requested label matching doesn't allow to build an unambiguous result, Prometheus just fails the query. PromQL many-to-one and one-to-many vector matching - arithmetic and comparison operations (clickable, 1.2 MB). Logical (aka set) binary operators and, unless, and or surprisingly adhere to a simpler vector matching logic. These operations are always many-to-many. Hence no group_left or group_right may be needed.
🌐
Grafana
grafana.com › blog › 2024 › 12 › 13 › promql-vector-matching-what-it-is-and-how-it-affects-your-prometheus-queries
PromQL vector matching: what it is and how it affects your Prometheus queries | Grafana Labs
December 14, 2024 - We have many vectors on the left side that match one vector on the right side — that’s many-to-one matching. In this case, we have to show Prometheus from which side we want our labels (which side represents the “many”), using group_left or group_right keywords.
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
Find elsewhere
Top answer
1 of 2
6

The RHS has no instance label, so it's trying to match all those series to one on the LHS. Try max by (node, instance) (kube_node_labels{label_grid="true"})

2 of 2
2

The group_left() modifier expects that the right-hand side of * operator (and any other operator) contains only a single time series per each label=value set specified inside on() modifier. Otherwise it returns duplicate series for the match group error. See these docs for more details.

The solution is to specify the proper labels inside on() modifier, so every label=value set for these labels would have only a single time series on the right-hand side of * operator. The instance label is a good candidate to put inside on() modifier. The only issue is that the dcgm_gpu_utilization and kube_node_labels are collected from different targets with different TCP port numbers. So they have different instance label values (see these docs explaining how instance label is generated). This breaks matching rules for * operator, so the following query returns nothing:

floor(avg_over_time(dcgm_gpu_utilization{cluster_name="researchers"}[5m]))
  * on (instance) group_left(node)
kube_node_labels{label_grid="true"}

This can be fixed by stripping the port number from instance label at both sides of * operator with the help of label_replace function:

label_replace(
  floor(avg_over_time(dcgm_gpu_utilization{cluster_name="researchers"}[5m])),
  "hostname",
  "$1",
  "instance",
  "([^:]+):.+"
)
  * on (hostname) group_left(node)
label_replace(
  kube_node_labels{label_grid="true"},
  "hostname",
  "$1",
  "instance",
  "([^:]+):.+"
)

This query extracts hostname part from instance labels, puts it into a hostname label and then joins the left-hand side and the right-hand side time series on this label.

🌐
Last9
last9.io › blog › prometheus-group-by-label
Prometheus Group By Label: Advanced Aggregation Techniques for Monitoring | Last9
June 12, 2026 - group_left is used when the left side of a vector match has more time series than the right. group_right is for the opposite case—when the right side has more time series. These are used to join metrics that have different cardinalities, such ...
🌐
Grafana
grafana.com › blog › 2021 › 08 › 04 › how-to-use-promql-joins-for-more-effective-queries-of-prometheus-metrics-at-scale
How to use PromQL joins for more effective queries of Prometheus metrics at scale | Grafana Labs
August 5, 2021 - groups: - name: slo_metric expr: count by (reference_label) ((api_response_latency * on (labelone,labeltwo) group_left(reference_label) sli_info > 100) This would work for every metric with those label names and associated mappings. Voila! You get the same result as the existing rule group, without the 18,000 individual rules. Tags · PrometheusPromQL ·
🌐
Google Groups
groups.google.com › g › prometheus-users › c › KmPqvJuFoHY
turning a group_left use of info-block into a range vector
device_boot_time * on (instance) group_left(region, firmware) device_info{region="California", firmware="v1.0"} Even through seems to return an instant value - I have not been able to figure out if it is possible to turn into a range vector · What you want to do is the range vector operation, and then the group_left:
Top answer
1 of 1
1

It is OK to use group_left() for 1:1 query if you need retaining all the labels from time series on the left side (or from the right side if group_right() is used). This doesn't introduce performance penalty.

If you put a list of labels inside group_left(), then these labels will be copied from time series on the right side additionally to all the labels from time series on the left side of the specified binary operator.

See more details in the official docs.

If you need retaining only some labels from the left side, then just drop unneeded labels after the calculations of q1 * on (...) group_left() q2. Prometheus doesn't provide functions, which can drop unneeded labels from time series (or leave only the needed labels), but this functionality can be emulated with sum(...) without (...) or sum(...) by (...) in most cases. For example, the following query leaves only (namespace, instance_id, label2) labels from time series matching metric1{namespace="ns1"} in the result:

sum(
  (metric1{namespace="ns1"} == 1)
    * on (namespace, instance_id) group_left()
  (metric2{namespace="ns1", label3="something"} == 1)
) by (namespace, instance_id, label2)

Note that the sum() may return unexpected results if multiple time series have the same set of output labels specified inside by (...).

P.S. Take a look also at label_del and label_keep functions provided by VictoriaMetrics - the Prometheus-like monitoring solution I work on. These functions are easier to use instead of sum(...) by (...) or sum(...) without (...) trick when some labels need to be dropped / left in the result.

🌐
Coralogix
coralogix.com › home › promql tutorial: 5 tricks to become a prometheus god
PromQL Tutorial: 5 Tricks to Become a Prometheus God
June 3, 2025 - We can change the way vectors a and b are matched using labels. For instance, the query a * on (foo, bar) group_left(baz) b matches vectors a and b on metric labels foo and bar.
🌐
OneUptime
oneuptime.com › home › blog › how to join two metrics in prometheus query
How to Join Two Metrics in Prometheus Query
December 17, 2025 - When the right side has fewer elements (lower cardinality), use group_left() to allow the many-to-one match and optionally include labels from the right side in the result.
🌐
Promlabs
promlabs.com › promql-cheat-sheet
PromLabs | PromQL Cheat Sheet
Available aggregation operators: sum(), min(), max(), avg(), stddev(), stdvar(), count(), count_values(), group(), bottomk(), topk(), quantile() ... Only keep series from the left-hand side whose sample values are larger than their right-hand-side matches:
🌐
Last9
last9.io › blog › promql-cheat-sheet
PromQL Cheat Sheet: Queries, Functions, and Labels | Last9
September 12, 2024 - Sometimes, you might want to join time series from two different metrics, but they don’t have matching labels. In that case, you can use group_left() or group_right() to indicate how to join them.