High cardinality describes a field with a very large number of distinct values, such as user IDs, email addresses or request IDs. In metrics systems, each unique combination of labels creates a separate time series, so a high-cardinality label multiplies storage and query cost. Keep such values in logs or traces instead.
What does cardinality mean here?
The Prometheus naming guide states the rule directly: every unique combination of key-value label pairs represents a new time series, which can dramatically increase the amount of data stored. Its caution reads: do not use labels to store dimensions with high cardinality, "such as user IDs, email addresses, or other unbounded sets of values".
OpenTelemetry's metrics SDK specification uses the same word. It defines cardinality as the number of unique combinations of attributes, and says SDKs should support a cardinality limit, a hard limit on the number of metric points collected in a collection cycle. It also says enforcement should happen after attribute filtering, so users can drop unwanted attributes before they hit the limit.
How does it grow?
Multiply the distinct values of each label. A counter of requests with labels for service (20 values), endpoint (50), status code (10) and region (4) gives up to 40,000 series. That is manageable. Add a user ID label with 100,000 users and the same counter can reach four billion combinations in the worst case. In practice, you see only the combinations that occur, but the growth is still brutal.
The costs show up as memory pressure on the metrics server, slow queries, larger bills with hosted services, and sometimes dropped data when a limit is reached.
Why does it matter for security teams?
Security telemetry wants rich detail: which user, which IP, which request. That is the opposite of what metrics storage handles well. A common mistake is to build an alert on "failed logins per user" as a metric with a user label. An attacker spraying passwords across thousands of accounts also creates thousands of new series.
Constructed example: a team adds a client IP label to a login failure counter. During a credential stuffing run, the number of series jumps from a few hundred to millions in an hour. The metrics server runs out of memory, and the monitoring that should have caught the attack goes dark. The better design keeps a counter with a small label set, and sends per-IP detail to logs.
Where should high-cardinality data go?
Logs and events hold detail for individual records. They are built for search by value.
Traces follow one request across services, and can carry an ID per request.
Exemplars link a metric point to a trace, so you jump from a spike to an example without adding a label.
Aggregation in code. Reduce a value to a bucket: status class instead of every code, country instead of city, plan tier instead of customer ID.
What about cost control after the fact?
If a label has already exploded, you do not have to wait for a code change. Most collectors and SDKs let you drop or rewrite an attribute at the pipeline stage. OpenTelemetry's specification says cardinality limits should be enforced after attribute filtering, which means a filter that removes a label in time keeps you below the cap. Fix the instrumentation afterwards, and add the check to review so it does not return.
How to check or apply this
- List the labels on your top ten metrics, and estimate the distinct values of each.
- Multiply them. If the product is beyond what your system handles, remove or bucket a label.
- Never use IDs, emails, URLs with parameters or timestamps as labels.
- Set a cardinality limit in your SDK or collector, and alert when you approach it.
- Move per-entity detail to logs or traces, and link them by trace ID.
- Review new metrics in code review with a short cardinality question.
Quick check
Is high cardinality always bad?
No. It is a fact about the data. It is a problem in systems built for low-cardinality aggregates, such as time series metrics. Log and trace stores are designed to hold it.
How can you spot a cardinality problem early?
Watch the count of active series and memory use. A steady jump after a deploy usually points to a new label.
Sources
Last reviewed: 18 October 2026.