Back to Blog
Prometheus
Grafana
Cardinality
Performance
Prometheus: How We Slashed Memory Usage - And Discovered Our Dashboards Were the Real Problem
January 17, 2026
8 min read
Prometheus doesn’t wake up one morning and decide to eat your RAM.
It doesn’t randomly jump from “healthy” to “why is this pod requesting 64GB?”
When memory spikes, it’s almost always earned.
And in the story behind “Prometheus: How We Slashed Memory Usage,” the villain wasn’t traffic, or scale, or some exotic bug in the TSDB.
It was dashboards .
Specifically, high-cardinality metrics and labels powering Grafana panels that no one had seriously audited in a long time.
This wasn’t a tale of tweaking retention flags or flipping obscure storage settings. It was a forensic investigation into what was actually sitting inside the head block — and why.
---
## The Moment You Realize It’s Not “Just Growth”
Every Prometheus operator knows the feeling.
Memory creeps up slowly. You assume it’s organic growth. More services. More pods. More metrics. That’s the cost of scaling.
But when usage starts climbing disproportionately to workload growth, something’s off.
That’s where this story begins .
Instead of throwing hardware at the problem, the team dug into cardinality. They treated memory usage as a symptom, not a root cause.
And what they found is painfully familiar.
---
## High Cardinality: The Silent Multiplier
Prometheus memory is heavily influenced by the number of active time series.
More unique label combinations = more time series.
More time series = more memory.
It’s brutally linear.
The team focused on identifying high-cardinality metrics and labels, particularly the ones used by Grafana dashboards .
That detail is key.
Because dashboards have a way of quietly justifying bad metrics design.
Someone adds a panel that slices by `user_id` or `request_path`.
It looks cool.
It answers a debugging question.
Nobody asks whether it belongs in a production metric.
Weeks pass.
Deployments multiply.
Pods churn.
Now that “temporary” label has exploded into tens of thousands of distinct series.
And Prometheus dutifully stores them all.
---
## Grafana Isn’t the Villain — But It Enables Bad Habits
Let’s be clear: Grafana didn’t cause the problem.
But dashboards create incentives.
When a panel requires a certain label to function, engineers are reluctant to remove that label — even if it’s ballooning cardinality.
The article describes analyzing which metrics and labels were actually used by dashboards .
That’s a subtle but powerful move.
Not “what metrics exist?”
Not “what labels are large?”
But:
“What labels are justified by real usage?”
If a label isn’t meaningfully powering dashboards or alerts, why is it in memory?
---
## PromQL as a Scalpel
The article promises helpful PromQL queries for finding high-cardinality metrics .
That’s the part most teams skip.
They feel the pain.
They assume they know the cause.
They start deleting exporters or adjusting scrape intervals.
But PromQL lets you see:
- Which metrics have the most series.
- Which labels have the highest distinct value counts.
- Which combinations are exploding.
When you query your own Prometheus about itself, you stop guessing.
You start measuring the cost of each label.
And that’s where discipline begins.
---
## The Real Shift: From “Collect Everything” to “Collect Intentionally”
A lot of Kubernetes-based setups start with broad defaults:
- kube-state-metrics
- cAdvisor
- Node exporter
- Ingress controllers
- Service meshes
All scraping. All exporting. All with rich labels.
And it works — until it doesn’t.
The story here isn’t about cutting Prometheus features.
It’s about pruning metrics that were technically available but practically unnecessary .
That’s a mindset change.
Observability culture often pushes “collect now, analyze later.”
But Prometheus punishes that mentality.
It doesn’t compress your indecision.
It keeps every series hot in memory.
---
## Dashboards as Technical Debt
Here’s the uncomfortable angle.
Dashboards accumulate like code.
Someone creates one for an incident.
Another team clones it.
A third adds a new label to improve granularity.
Soon, you have dozens of panels depending on subtle label combinations that no one remembers justifying.
Removing a label suddenly feels risky.
“What if that dashboard breaks?”
“What if someone needs that breakdown during an outage?”
So the label stays.
And memory climbs.
By tracing cardinality back to dashboard usage , this team reframed the question.
Instead of asking:
“Can we afford to remove this label?”
They asked:
“Is this label earning its cost?”
That’s a different energy.
---
## Slashing Memory Isn’t About Flags
There’s a temptation when Prometheus gets heavy to look for runtime tweaks:
- Adjust retention.
- Tune compaction.
- Increase scrape interval.
- Enable compression flags.
Those can help.
But they don’t fix cardinality.
High cardinality is structural.
You can’t GC your way out of bad metric design.
The story here centers on reducing series count by eliminating unnecessary high-cardinality labels .
That’s not a config change.
That’s architecture.
---
## The Hidden Cost of “Just One More Label”
Engineers love labels.
They make metrics flexible.
They make slicing easy.
They make dashboards powerful.
But every new label dimension multiplies potential series.
A metric with:
- 10 services
- 5 status codes
- 3 regions
That’s 150 possible series.
Add `user_id` with 10,000 possible values?
Now you’re at 1.5 million.
That’s not theoretical.
That’s how memory disappears.
And the worst part?
Most dashboards don’t need that breakdown.
It’s there because it might be useful.
Prometheus doesn’t optimize for “might.”
It optimizes for “you asked for it.”
---
## What This Story Really Teaches
The article frames it as slashing memory usage .
But the deeper lesson is this:
Observability systems need governance.
Without it, metrics sprawl the same way logs do.
Dashboards grow unchecked.
Labels multiply.
Memory follows.
You don’t need exotic tooling to fix it.
You need:
- Visibility into series counts.
- Willingness to question dashboard assumptions.
- The discipline to remove labels that aren’t pulling their weight.
---
## Prometheus Scales — If You Respect It
There’s a recurring pattern across these memory stories.
Prometheus rarely fails because it’s incapable.
It fails because it’s permissive.
It will happily store millions of series if you tell it to.
It will happily index every dynamic label.
It will not stop you.
And that’s the trap.
In this case, the team turned inward and audited their own metric hygiene .
They didn’t blame the TSDB.
They didn’t immediately reach for a different time-series database.
They asked:
“What are we storing — and why?”
That question alone is powerful.
---
## If Your Prometheus Is Getting Heavy
Ask yourself:
- Which metrics have the highest series count?
- Which labels explode in value cardinality?
- Are those labels actually required by dashboards or alerts?
- Are dashboards driving metric design instead of the other way around?
- Are you exporting labels that change every deploy?
If you don’t know the answers, your memory graph probably does.
And it’s climbing.
Slashing memory usage isn’t magic.
It’s subtraction.
And sometimes, the fastest way to make Prometheus lighter is to admit you’re measuring more than you need.
Keep Exploring
How One Team Slashed Prometheus Memory From 60GB to 20GB - And Exposed the Silent Cardinality Crisis
A real case study on cutting Prometheus memory usage from 60GB to 20GB by identifying toxic labels and reclaiming scrape reliability.
Prometheus Counters Are Not Broken - But They Are Breaking Teams Who Treat Them Like Datadog
Why counter semantics confuse teams during Datadog to Prometheus migrations, and the query patterns that avoid silent misreads.
Because Real Heroes Build Their Own Exporters - And Sometimes That Is Exactly the Right Move
Building a custom exporter can be the fastest path to useful observability when critical systems lack stable community integrations.
Why I Recommend Native Prometheus Instrumentation Over OpenTelemetry - And Why That Title Sparked a Fight
A focused argument for native Prometheus metrics instrumentation in specific scenarios, with clear boundaries on where OpenTelemetry remains the better fit.