What Is Aggregation Temporality in OpenTelemetry?
Learn how OpenTelemetry decides whether a metric reports the grand total since the beginning or only what changed since the last report, and why that one choice shapes your memory use, your costs, your dashboards, and your choice of backend.
Think about the dashboard of a car. There are two number displays that look almost the same but answer very different questions. The odometer says how far the car has travelled in its whole life, say 48,210 kilometres. The trip meter says how far you have driven since you last pressed the reset button, say 37 kilometres. Both are honest. Both are measuring distance. The only difference is the starting point of the counting.
Now imagine thousands of cars, each sending one of these numbers to a control room every minute. If some cars send the odometer and others send the trip meter, and the control room does not know which is which, the control room will produce nonsense. That is exactly the problem OpenTelemetry solves with a small but powerful idea called aggregation temporality. In this guide we will build the idea from the ground up, look at how it works inside the pipeline, and learn how to choose the right setting for real systems.
1The Metrics Basics You Need First
Before we talk about time, we need a shared vocabulary for how OpenTelemetry turns application behaviour into numbers.
OpenTelemetry, often shortened to OTel, is an open standard for producing and moving telemetry data out of software. Telemetry comes in several signals: traces describe the journey of a single request, logs describe individual events, and metrics describe numbers that summarise behaviour over time. Metrics are the cheapest of the three to store, which is why teams use them for dashboards and alerts. Aggregation temporality lives entirely inside the metrics signal.
Your application does not talk to a metrics backend directly. Instead, your code uses an API to record what happened, and a separate SDK decides how to summarise those recordings and ship them out. This separation is deliberate. Library authors can add instrumentation using only the API, and the people who run the application decide later, through SDK configuration, where the data goes and in what form.
Instrument
The object your code uses to record a number, such as a counter for requests handled or a histogram for response times.
Measurement
One single recorded value, for example “this request took 230 milliseconds”. Measurements are raw and very numerous.
Attributes
Key and value labels attached to a measurement, such as the route name or the status class. Each unique set of labels forms its own series.
Aggregation
The rule for squashing many measurements into one compact summary, such as adding them up or sorting them into buckets.
Data Point
The summary that actually leaves the SDK: a value (or bucket counts) plus timestamps and the attributes it belongs to.
Metric Reader
The SDK component that collects data points on a schedule or on request and hands them to an exporter.
Picture a shop with a tally clerk at each till. Every sale is a measurement. The clerk groups sales by department, which are the attributes. At the end of each reporting round, the clerk hands the manager a single sheet with one line per department. That sheet is the data point. How the clerk writes the numbers on that sheet, as a running total or as “since the last sheet”, is the whole subject of this guide.
One more idea matters here. Each unique combination of a metric name and attribute values is called a time series. If your request counter has an attribute for the route and the route can be one of ten values, you have ten series. The SDK keeps one running summary per series, and as we will see later, whether it keeps that summary forever or forgets it regularly is directly controlled by temporality.
2So, What Is Aggregation Temporality?
It is the rule that says which stretch of time a reported metric value covers.
Whenever the SDK summarises measurements, two separate questions must be answered. The first question is what mathematical operation to use: add the values, remember the last value, or count how many fell into each bucket. That is the aggregation. The second question is over which period the operation applies: everything since the application started, or only since the previous report. That is the temporality. The word comes from “temporal”, meaning related to time.
The OpenTelemetry data model defines exactly two answers to the second question. In cumulative temporality, every report covers the period from a fixed starting moment up to the present, so each new report contains everything the earlier ones did, plus the latest activity. In delta temporality, every report covers only the period since the previous report, so each report stands alone and the starting moment moves forward each time.
| Question | Handled by | Example answers |
|---|---|---|
| How are measurements combined? | Aggregation | Sum, last value, explicit-bucket histogram, exponential histogram |
| Over which time window? | Aggregation temporality | Cumulative (since a fixed start) or delta (since the last report) |
| How often is data sent? | Export interval | Every 10 seconds, every 60 seconds |
Temporality is not the same as how frequently you export. You can export a cumulative metric every second or every hour, and it is still cumulative. The export interval only controls how often you get a snapshot, while temporality controls what the snapshot means.
It also helps to know that temporality is a property of the data on the wire, not of the instrument in your code. Your developers call the same add method on a counter regardless of which temporality the operators chose. That is a major design win: instrumentation code never needs to change when you move from one backend to another that prefers a different style.
3The Two Flavors: Cumulative and Delta
Two ways of writing the same truth on the report sheet.
Cumulative
Each data point carries the running total since a fixed start time. Values only go up for monotonic counters, until a restart resets them.
Delta
Each data point carries only the change since the previous data point. The start time of one point equals the end time of the one before it.
A bank passbook shows your balance after every transaction, so any single line tells you the full position. That is cumulative. A list of today’s deposits and withdrawals tells you only what changed since yesterday. That is delta. If you lose one page of the passbook, the next page still shows the correct balance. If you lose one page of the daily change list, your running balance is now wrong forever unless somebody corrects it.
Why two flavors exist at all
Different tools in the observability world grew up with different habits. Prometheus, one of the most influential metrics systems, stores ever-growing counters and expects the query layer to work out rates. Other systems, especially ones born in the era of StatsD, store the number of events per interval and simply add them up when you query. OpenTelemetry wanted to speak to both worlds without forcing everyone into one style, so the data model includes a field that declares the temporality of each metric stream, and the SDK can be configured to produce either.
The same activity, written two ways
Suppose a service handles 120 requests in the first minute and 90 in the second. A cumulative stream reports 120 and then 210. A delta stream reports 120 and then 90. A person reading the delta stream must add to find the total. A person reading the cumulative stream must subtract to find the activity of one minute. Neither is more correct. They are two lenses on the same facts, and each lens makes certain questions easier and certain failures more painful.
| Aspect | Cumulative | Delta |
|---|---|---|
| What a point means | Total since a fixed start | Change since the last report |
| Start time across points | Stays constant | Moves forward each time |
| Effect of a lost report | Next report repairs the gap | The lost activity is gone |
| State kept in the SDK | Grows with every series ever seen | Can be cleared after each report |
| Natural query style | Compute a rate or an increase | Add the values over the window |
| Default in the SDK | Yes | Opt in |
4Timestamps: The Secret Language of Temporality
Every data point carries two clocks, and together they tell you everything.
Inside a metric data point there are two timestamps. The start time marks the beginning of the period the point describes. The time, sometimes called the end time, marks the moment the value was captured. The relationship between these two timestamps across successive points is what makes temporality visible. You do not need to guess the flavor by looking at numbers, because the pattern of the timestamps reveals it.
flowchart TB
subgraph CUM["Cumulative: the start time stays fixed"]
direction LR
C1["Point 1: T0 to T1"] --> C2["Point 2: T0 to T2"] --> C3["Point 3: T0 to T3"]
end
subgraph DEL["Delta: the start time moves forward"]
direction LR
D1["Point 1: T0 to T1"] --> D2["Point 2: T1 to T2"] --> D3["Point 3: T2 to T3"]
end
In the cumulative picture, every window begins at the same moment, usually the time the SDK first saw the series or the time the process started. Each window is longer than the last, because it stretches further into the present. In the delta picture, windows sit side by side like tiles on a floor. The end of one tile is exactly the beginning of the next, with no overlap and no gap.
Why the start time matters so much
The start time is what lets a consumer detect a counter reset. If a cumulative series reports a total of 5,000 and then a total of 40, a careful consumer looks at the start time. If the start time jumped forward, the process restarted and the counter began again from zero, so the 40 is new activity and nothing was lost. Without a trustworthy start time, the consumer would see a mysterious drop and could not tell a restart from a bug. Prometheus-style systems infer resets purely from a value going down, while the OpenTelemetry model gives the extra hint of an explicit start time.
Reading a data point step by step
Check the temporality field
The metric stream declares itself as cumulative or delta. A third value, unspecified, exists for legacy data and should be treated with suspicion.
Look at the start time
For cumulative, compare it with earlier points to spot restarts. For delta, confirm it lines up with the previous end time.
Look at the end time
This is the moment the value was observed, and it places the point on the time axis of your charts.
Interpret the value
Only now does the number have meaning: a total over the whole span for cumulative, or an increment for just that span for delta.
5Which Metric Types Care About Temporality
Not every kind of metric has a “since when” question to answer.
The OpenTelemetry metrics data model defines several metric types, and temporality applies only to some of them. The ones that accumulate something over a period carry a temporality, and the ones that simply capture a moment do not. Understanding this split prevents a lot of confusion, because people often search for a temporality switch on gauges and cannot find one.
Sum
A total of values, produced by counters and up-down counters. It also records whether the sum is monotonic, meaning it can only increase.
Histogram
Counts of measurements falling into value ranges (buckets), plus a total count and usually a sum of all values.
Exponential Histogram
A histogram whose bucket boundaries grow on a logarithmic scale, giving good precision across huge ranges with a compact size.
Gauge
The latest observed value at an instant, such as current memory in use. There is no period being accumulated.
Summary
Precomputed quantiles carried over from older systems. It exists mainly for compatibility, and the SDKs do not generate it for new instrumentation.
A thermometer reading is a gauge. It says “right now it is 31 degrees”, and asking “since when?” makes no sense. Rainfall is a sum. “40 millimetres” is meaningless until you say whether you mean this morning, this month, or this year. Temporality is the label that says which one.
The special case of up-down counters
An up-down counter measures something that can rise and fall, such as the number of items currently in a queue or the number of active connections. It is still a sum, so it still has a temporality. But a delta stream of an up-down counter is awkward to use, because each point only says how much the value moved, and you need the full history of moves to know the current level. For this reason, several of the standard preference modes keep up-down counters cumulative even when everything else is delta, a detail we will return to in Chapter 8.
When someone says “my histogram is delta”, they mean the bucket counts in each point cover only one reporting window. That makes the distribution of that single window easy to read, which is one of the practical attractions of delta histograms.
6A Worked Example With Real Numbers
Let us follow one counter through five minutes and one restart.
Imagine a checkout service that counts every order request it handles. The SDK exports once per minute. In minute one the service handles 120 requests, in minute two 90, in minute three 150, in minute four none at all because it is the middle of the night for most customers, and in minute five 60. Here is how the same story looks in the two flavors.
| Minute | Real activity | Cumulative value reported | Delta value reported |
|---|---|---|---|
| 1 | 120 requests | 120 | 120 |
| 2 | 90 requests | 210 | 90 |
| 3 | 150 requests | 360 | 150 |
| 4 | 0 requests | 360 | 0 or no point at all |
| 5 | 60 requests | 420 | 60 |
The quiet minute
Minute four is instructive. In cumulative temporality the series keeps reporting 360, a flat line that clearly says “nothing new happened”. In delta temporality, SDKs commonly skip series that had no activity in the window, so the point may simply not be sent. A dashboard that treats a missing delta point as an unknown rather than a zero can show a gap, while a dashboard that treats it as zero shows the truth. This is why delta consumers must be written with care about missing points.
The restart
Now suppose the process restarts between minute five and minute six and handles 40 requests in minute six. The delta stream just reports 40, and nothing special happens, because delta streams have no running total to lose. The cumulative stream reports 40 with a new, later start time. A consumer sees the total drop from 420 to 40, notices the start time moved, and correctly concludes the counter was reset. If the consumer is naive and simply subtracts consecutive values, it would compute a negative number of requests, which is why proper rate functions include reset handling.
Think of a school that records how many pupils entered the gate. A cumulative register says “1,420 pupils this term”. If a new register book is started mid-term, the first page says “12 pupils” and everyone understands a fresh book began. A daily sheet saying “12 pupils today” never needed such an explanation.
The same idea for histograms
For a latency histogram, the story is identical but with bucket counts instead of a single number. A cumulative histogram reports how many requests have ever fallen into each bucket since the start. A delta histogram reports how many fell into each bucket during the last minute only. If you want to know whether latency got worse in the last minute, the delta histogram answers it directly, whereas the cumulative one needs you to subtract the previous snapshot bucket by bucket before you can see the recent shape.
7Where Temporality Gets Decided in the Pipeline
A metric passes through several hands before it is stored, and each hand has a say.
flowchart LR
A["Application code records measurements"] --> B["SDK instruments"]
B --> C["Aggregation per series"]
C --> D["Metric reader applies temporality preference"]
D --> E["OTLP exporter"]
E --> F["Collector with optional conversion"]
F --> G["Backend storage and queries"]
The first and most important decision point is the metric reader inside the SDK. Each reader is configured with a temporality preference, which is a rule that maps every instrument type to either cumulative or delta. Because readers are separate objects, one SDK can have several readers with different preferences, for example one that feeds a local Prometheus endpoint with cumulative data and another that exports to a remote vendor with delta data. The aggregation is computed independently for each reader.
The second decision point is the exporter configuration. In practice, most teams set the preference through an environment variable on the OTLP metrics exporter, so operators can change it without rebuilding the application. The third point is the Collector, which can receive data in one temporality and convert it to another using processors. The fourth point is the backend, which decides what it can accept and what it does with the data.
Record
Code calls the instrument. Nothing about temporality is visible here, which keeps application code portable.
Aggregate
The SDK folds measurements into one summary per unique attribute set, using the chosen aggregation.
Collect
On each export tick, the metric reader gathers summaries and applies the temporality preference, either keeping state (cumulative) or resetting it (delta).
Transport and convert
Data travels over OTLP. A Collector may convert between flavors if the destination needs something different.
Store and query
The backend stores the points and answers questions, using logic that assumes a particular temporality.
Aggregation and temporality are separate configuration knobs. Views in the SDK let you change the aggregation of an instrument, such as switching a histogram from explicit buckets to exponential buckets. The temporality preference is chosen independently on the reader. Changing one does not change the other.
8Instrument Types and the Three Preference Modes
The standard configuration gives you three ready-made recipes.
OpenTelemetry has two families of instruments. Synchronous instruments are called by your code at the moment something happens, such as a counter increment when a request arrives. Asynchronous instruments, also called observable instruments, are read by a callback that the SDK triggers at collection time, such as a gauge reading current memory or a counter reading a total maintained elsewhere. This split matters for temporality, because it changes what the SDK knows and what it has to remember.
The specification and the SDKs recognise three named preferences for the OTLP exporter, usually selected through an environment variable on the metrics exporter. Cumulative is the default, and it reports every instrument cumulatively. Delta reports delta for counters, observable counters, and histograms, while keeping up-down counters and observable up-down counters cumulative. The low-memory preference reports delta only for synchronous counters and histograms, keeping everything else cumulative.
| Instrument | Cumulative preference | Delta preference | Low-memory preference |
|---|---|---|---|
| Counter | Cumulative | Delta | Delta |
| Up-down counter | Cumulative | Cumulative | Cumulative |
| Histogram | Cumulative | Delta | Delta |
| Observable counter | Cumulative | Delta | Cumulative |
| Observable up-down counter | Cumulative | Cumulative | Cumulative |
| Observable gauge | Not applicable | Not applicable | Not applicable |
Why the low-memory mode exists
Observable counters present an interesting puzzle. Your callback reports the current absolute total, for example “this process has read 9,800,000 bytes so far”. To turn that into a delta, the SDK has to remember the previous reading for every series and subtract. That remembered state is exactly the memory cost that delta temporality is supposed to eliminate. So the low-memory preference leaves observable instruments cumulative and applies delta only where the SDK can genuinely drop state after each export.
Why up-down counters stay cumulative
As described earlier, a delta up-down counter only tells you the movement, so consumers need every point to reconstruct the level. Losing one point permanently corrupts the level. Keeping these instruments cumulative avoids that fragility, and that is why even the delta preference leaves them alone.
Imagine three recipes for a restaurant’s end-of-day report. The cumulative recipe says “write the running total for everything”. The delta recipe says “write today’s change for everything that makes sense as a change”. The low-memory recipe says “write today’s change only where the cashier can do it without keeping extra notes, and write totals for everything else”.
Language SDKs implement the specification with small differences in naming and defaults. Always confirm the exact environment variable behaviour and the available modes in the documentation of the SDK version you actually run.
9Cumulative Temporality in Depth
The safe, forgiving default, and the price it charges in memory.
With cumulative temporality, the SDK keeps a running summary for every series from the moment that series is first seen. At each export, it reads the current summary and sends it without clearing anything. The next export sends a summary that includes everything from before. This approach is conceptually simple, and it matches the way many classic metrics systems already work, which is why it is the default.
The strength: resilience to loss
Networks drop packets, Collectors restart, and exporters sometimes time out. In a cumulative stream, a lost report is a minor annoyance. The next report that arrives contains the full total, so the long-term picture is intact. The only thing lost is the resolution of the chart during the gap. Operators who value dependable totals, for billing-like counters or service level calculations, often rely on this property.
The strength: simple, stateless consumers
A backend that receives cumulative points does not need to remember anything about the sender to store a value. It can write each point independently. If many replicas of a service send data, each replica produces its own series, and the backend can combine them at query time. There is no need to ensure that all data from one sender lands on one machine.
The cost: memory that never shrinks
Because the total since the beginning must stay correct, the SDK can never forget a series. If a metric has an attribute that takes many different values over time, such as a user identifier or a temporary pod name, each new value creates a new series that stays in memory until the process ends. SDKs usually impose a cardinality limit and fold excess series into an overflow bucket, but that limit is a safety net, not a design goal.
Advantages
- A missed export does not permanently lose information
- Works with Prometheus-style systems directly
- Any single point shows the full total, which is easy to inspect by eye
- Consumers can be stateless and simple to scale
- Restarts are detectable through the start time
Disadvantages / Trade-offs
- The SDK keeps state for every series it has ever seen
- Idle series keep being reported, wasting bandwidth and storage
- Answering “what happened in the last minute” requires a subtraction step
- Resets must be handled correctly by every consumer
A cumulative metric is like a lifetime-attendance register that a school never throws away. It is trustworthy and any page shows the whole story, but the cupboard storing the old registers keeps getting fuller, even for children who left years ago.
10Delta Temporality in Depth
Lean and current, but unforgiving when something goes missing.
With delta temporality, the SDK accumulates measurements during a reporting window and, when it exports, sends the window’s summary and then resets its state. The next window starts from zero. The SDK therefore only needs to hold information about series that were active in the current window, and series that went quiet cost nothing at all.
The strength: bounded memory
The amount of memory in use tracks the number of series active in a single window, not the number of series ever seen. For short-lived or highly dynamic workloads, this can be the difference between a healthy process and one that slowly bloats. The SDK can also stop sending idle series, which reduces network traffic and storage in the backend.
The strength: easy window questions
Because each point is already a per-window amount, questions like “how many errors occurred in the last five minutes” turn into simple additions of the last few points. Histograms are even more attractive, because each point shows the true distribution of that window without any subtraction.
The cost: fragility and statefulness downstream
A lost delta point is permanently lost. No later report will repair the total, and the long-term sum quietly under-counts. Delta data also pushes complexity downstream, because anything that wants a running total, such as converting back to cumulative for a Prometheus-style store, must remember the previous total and see every point in order. When several replicas report into a pipeline of several Collector instances, the points of a single series must all reach the same instance or the arithmetic breaks.
Advantages
- SDK memory follows active series, not historical series
- Idle series produce no traffic
- Per-window questions are answered by simple addition
- Per-window histograms reveal recent latency shape directly
- A natural fit for short-lived processes that may never export twice
- Preferred by several commercial vendors
Disadvantages / Trade-offs
- Lost or dropped points permanently distort totals
- Not accepted directly by every Prometheus-style system
- Converting to cumulative needs state and ordered delivery
- Missing points can be misread as zero or as outages by dashboards
A delta metric is like a daily sales slip that the cashier hands over and then throws away. The cupboard stays empty and tidy. But if the manager misplaces one slip, that day’s sales never appear in the monthly total, and nobody can recover them from the till.
11Memory, Cardinality, and the Cost Story
Temporality is one of the quiet levers behind your observability bill.
Cardinality is the number of distinct series a metric produces. It is the product, roughly, of the number of distinct values each attribute can take. A request counter with a route attribute of 20 values and a status attribute of 5 values can produce up to 100 series. Add a customer identifier with 50,000 values, and you may have five million. Every series costs memory in the SDK, bytes on the wire, and storage and indexing effort in the backend.
Temporality interacts with cardinality in three ways. First, inside the SDK, cumulative keeps all series forever while delta keeps only recent ones. Second, on the wire, cumulative re-sends idle series at every interval, while delta does not. Third, in the backend, both temporalities create the same number of distinct series for the same active workload, so delta is not a cure for a cardinality explosion, only a way to limit its lingering effects.
Churn: the hidden multiplier
Churn means series appear and disappear frequently, as happens when containers are replaced often and each carries a unique name in its attributes. Under cumulative temporality in a long-running process, churn from within the process fills the SDK memory. Under delta, churned series simply fade out after their last active window. In both cases, the backend still sees a continuous stream of brand new series, which is why resource attributes that change on every deployment should be chosen carefully.
Switching to delta temporality in the hope of fixing a cardinality problem. The real fix is to remove or bucket the high-variety attributes, or to use SDK views to drop them. Temporality only changes how long state is retained, not how many series are created while the workload is active.
Where memory matters most
A long-running gateway process that sees millions of distinct client addresses benefits most from delta or from tight attribute filtering, since cumulative state would grow for the whole lifetime of the process.
Where memory matters least
A small internal service with a handful of stable attribute values gains almost nothing from delta in memory terms, so the default cumulative setting is perfectly adequate and simpler to reason about.
12How Real Backends Treat Temporality
The best setting is often decided by the system on the receiving end.
A metric stream is only useful if the destination understands it. Backends differ widely in what they accept, and the temporality chosen at the source must match the destination’s expectations or be converted along the way. The following examples describe common patterns in the industry. Because products change quickly, treat these as orientation and confirm the current behaviour in each vendor’s own documentation.
Prometheus-style stores
The Prometheus world is built around cumulative counters, and its query functions for rates and increases assume ever-growing values with reset detection. Pipelines that end in a Prometheus-compatible system normally need cumulative data. Support for ingesting delta data natively has been an area of active development, so check the version you run before relying on it.
Vendors that favour delta
Several commercial observability platforms, including some well-known ones, document delta temporality as their preferred or even required form for counters and histograms, because it matches their internal storage and keeps client memory low. Sending them cumulative data may be converted on their side, rejected, or produce unexpected results depending on the product.
Short-lived and serverless workloads
Functions that start, handle one event, and stop within seconds may export only once. A cumulative series with a start time equal to the invocation start would create a new series per invocation. Delta avoids the notion of a long-lived total and tends to suit this pattern, usually with a Collector or backend that aggregates across invocations.
Fan-out to multiple destinations
Some teams send the same metrics to a Prometheus-compatible store and to a vendor with different needs. They either configure two readers in the SDK with different preferences, or send one temporality to a Collector and convert for each destination using processors.
| Destination type | Typical expectation | Practical advice |
|---|---|---|
| Prometheus-compatible storage | Cumulative | Keep the default or convert to cumulative before export |
| Delta-preferring vendor | Delta | Set the delta preference or follow the vendor guide exactly |
| Serverless pipeline | Delta, aggregated centrally | Use delta and aggregate in a Collector |
| Multi-destination fan-out | Mixed | Use multiple readers or per-pipeline conversion |
Start from the destination’s documentation, not from your own taste. Choose the temporality your backend expects, and only deviate when you have a specific reason and a conversion plan.
13Converting Between Temporalities in the Collector
When the sender and the receiver disagree, a translator can sit in the middle.
The OpenTelemetry Collector is a standalone service that receives, processes, and exports telemetry. Its contrib distribution includes processors that convert between the two flavors. One converts cumulative data into delta, and another converts delta data into cumulative. These let a platform team standardise on one temporality inside the company while serving destinations that need the other.
sequenceDiagram
participant S as SDK
participant C as Conversion processor
participant B as Backend
S->>C: Cumulative total 120
Note over C: First point, remember 120
S->>C: Cumulative total 210
C->>B: Delta 90
S->>C: Cumulative total 360
C->>B: Delta 150
S->>C: Cumulative total 40 after restart
Note over C: Value dropped, treat as a reset
C->>B: Delta 40
Cumulative to delta: remember the last value
To convert cumulative into delta, the processor stores the last total it saw for each series and subtracts it from each new total. This is straightforward, but it has two awkward moments. The very first point of a series has nothing to subtract from, so processors usually treat it specially, for instance by dropping it or by using the start time to decide. And when a total drops, the processor must decide whether that was a reset and how to account for it.
Delta to cumulative: add up everything, in order
To convert delta into cumulative, the processor keeps a running total per series and adds each delta to it. This demands that the processor sees every point of a series, in order, and that it never loses its state. If the Collector restarts, the running total restarts, and downstream consumers will see a reset that is an artefact of the pipeline rather than of the application.
Keep all points of a series together
When several Collector instances run in parallel, route data so that each series always lands on the same instance, for example by using a load-balancing exporter keyed on the series identity.
Plan for restarts
Remember that the converting Collector holds state in memory. A restart produces an artificial reset or a skipped first point, so avoid frequent restarts of that tier.
Convert as late as possible
Convert only at the edge that faces the destination which needs it. Keeping the rest of the pipeline in one temporality simplifies everything else.
Watch for memory growth
Conversion processors store per-series state, so they bring back the cardinality concern in the Collector itself.
Conversion moves the cost rather than removing it. Converting delta into cumulative in a Collector gives you the memory burden you tried to remove from the SDK, only now it lives in your pipeline.
14Querying and Reading the Data Correctly
The same question needs a different approach depending on the flavor.
Most mistakes with temporality do not happen in the SDK. They happen in dashboards and alerts, where someone writes a query that suits one flavor and runs it against the other. The key habit is to know, for every metric you chart, which temporality is stored, and to use the matching approach.
| Question you ask | On cumulative data | On delta data |
|---|---|---|
| How many events happened in the last 5 minutes? | Take the increase over the window, which subtracts the first value from the last and handles resets | Add up the points inside the window |
| What is the rate per second? | Use a rate function over a window | Divide the summed deltas by the window length |
| What is the lifetime total? | Read the latest value for each series and add across series | Add every point ever stored, which is expensive and fragile |
| Did latency worsen in the last minute? | Subtract the previous bucket counts from the current ones, then estimate quantiles | Estimate quantiles directly from the latest point |
The classic trap: charting the raw value
If you chart a raw cumulative counter, you see a line that climbs steadily and occasionally collapses to zero. It looks dramatic but tells you nothing about current load. The useful chart is the rate. Conversely, if you apply a rate function to a delta stream that your backend never converted, you may get meaningless results, because the function expects a growing series.
The subtle trap: summing across replicas
With cumulative data from many replicas, the right sequence is first to compute a rate per replica, which handles each replica’s own resets, and then to add the rates together. If you add the raw totals across replicas first and then compute a rate, a single replica restarting makes the combined total dip, and the rate function misreads it as a reset of the entire fleet. This is a well-known pitfall in the cumulative world, and delta temporality avoids it naturally.
Imagine reading the odometers of ten delivery vans. To find how far the fleet drove today, you subtract each van’s morning reading from its evening reading and add the ten answers. You do not add all ten odometers together first, because one van getting a new odometer would wreck the whole sum.
15Choosing the Right Temporality: A Decision Framework
A short set of questions that settles most real-world cases.
flowchart TD
A["Where are the metrics going?"] --> B{"Does the backend require cumulative?"}
B -->|Yes| C["Use cumulative"]
B -->|No| D{"Short lived or serverless workload?"}
D -->|Yes| E["Prefer delta"]
D -->|No| F{"Very high cardinality or heavy churn?"}
F -->|Yes| G["Consider delta or low memory, and filter attributes"]
F -->|No| H["Cumulative is a safe default"]
Read the destination’s requirements
If the backend only supports one flavor, the decision is already made. Everything else is optimisation.
Look at the lifetime of your processes
Long-running services suit either flavor. Very short-lived ones lean towards delta.
Estimate cardinality and churn
If attribute values vary widely and keep changing, cumulative state in the SDK can balloon. Reduce the variety first, then consider delta.
Judge your tolerance for lost data
If exact totals matter and the network is unreliable, cumulative gives a safety net that delta does not.
Decide where conversion will happen, if any
Place conversion at the edge of the pipeline and make sure sticky routing and state persistence are handled.
Document the choice
Write down which flavor is used where, so dashboards, alerts, and new teammates all use matching queries.
| Situation | Leaning | Main reason |
|---|---|---|
| Long-running service to a Prometheus-compatible store | Cumulative | Native fit and resilience |
| Serverless functions to a delta-preferring vendor | Delta | No long-lived totals and low memory |
| Gateway with huge numbers of changing client labels | Delta or low memory, plus attribute filtering | Bounded SDK memory |
| Billing-grade counters over a flaky network | Cumulative | Lost reports are repaired by the next one |
| Mixed destinations | Two readers or Collector conversion | Each destination gets what it expects |
16Monitoring, Security, and Operations
A telemetry pipeline is itself a production system and deserves care.
Watching the pipeline
Because temporality mistakes tend to fail quietly, you should monitor the telemetry pipeline itself. Track how many data points the SDK exports, how many the Collector receives, how many it refuses or drops, and how many the backend accepts. A sudden drop in accepted points after a configuration change is a classic sign that a backend is rejecting a flavor it does not support. A sudden jump in the number of series may mean an attribute with unbounded values was introduced.
For delta pipelines, pay extra attention to dropped data, since every dropped point is a permanent hole in your totals. For cumulative pipelines, watch memory in your applications and Collectors, since they accumulate state. For converted pipelines, monitor the memory and restart frequency of the converting tier.
Spot-checking the numbers
A healthy habit is to compare a metric against an independent source from time to time. For example, compare the total requests reported by your metric with the count in your load balancer’s own statistics for the same period. A persistent gap suggests lost delta points, a misconfigured conversion, or a query that treats one flavor as the other.
Security considerations
Temporality does not change the sensitivity of the data, but the surrounding setup deserves attention. Metrics travel over OTLP, and the connection between SDKs, Collectors, and backends should use encryption and authentication so that nobody can read or inject numbers. Attributes may carry sensitive information by accident, such as email addresses or account numbers, and since each unique value becomes a series, they are also a cardinality hazard. Keep such values out of metric attributes altogether.
Changing the temporality preference changes the meaning of the numbers that dashboards and alerts depend on. Treat it like a schema change: announce it, review it, and update the affected queries at the same time.
Gradual rollout
When migrating a fleet from cumulative to delta, change one service first, compare its dashboards against a still-cumulative sibling, and only then expand. This turns a risky global switch into a controlled experiment.
17Design Patterns and Anti-patterns
What works in practice, and the traps that catch even experienced teams.
Patterns that work
Match the destination
Pick the temporality your backend expects, and make that the single standard in the environment.
Convert at the edge
Keep one temporality across most of the pipeline, and convert only at the last hop before a destination that differs.
Per-reader preferences
Use separate SDK readers when two destinations need different flavors, so no Collector state is needed for the translation.
Control attributes first
Use views to drop or limit high-variety attributes before changing temporality for memory reasons.
Anti-patterns to avoid
Problem
Delta metrics are sent directly to a store that expects cumulative counters, or the reverse, with no conversion in between.
Why It’s Harmful
Rate functions return nonsense, totals appear far too small or too large, and alerts either never fire or fire constantly. The failure is quiet because the data still arrives and charts still draw lines.
Correct Approach
Confirm what the backend supports, set the temporality preference to match, or add a conversion step at the edge with sticky routing and monitored state.
Problem
Converting delta to cumulative across several unrelated Collector instances, with data from one series scattered between them.
Why It’s Harmful
Each instance builds its own partial running total, so downstream sees a jumble of values that rise and fall unpredictably, and every drop looks like a counter reset.
Correct Approach
Route all points of a series to the same instance, or perform the conversion in a single tier designed for it, and keep that tier stable.
Problem
Using temporality as a substitute for cardinality control, by adding user identifiers or request identifiers as attributes and relying on delta to keep memory low.
Why It’s Harmful
The backend still receives and stores an enormous number of series, costs rise sharply, and queries slow down. Only the SDK’s lingering memory improved.
Correct Approach
Keep identifiers out of metric attributes, use traces or logs for per-request detail, and apply views to limit allowed attributes.
Treating a missing delta point as an outage. In many SDKs, a series with no activity in a window is simply not exported. Alerts should be designed with that in mind, using explicit health signals rather than relying on the presence of every delta point.
18Frequently Asked Questions
Short answers to the questions people ask most often.
No. The export interval is how often data is sent. Temporality is what each sent value means, either a total since a fixed start or only the change since the last report. You can combine any interval with either flavor.
Cumulative is the default for the OTLP exporter in the standard specification. Delta and low-memory modes are opt-in through exporter configuration.
No. A gauge records the latest observed value at an instant, so there is no accumulation period to describe. Temporality applies to sums, histograms, and exponential histograms.
No. Instrumentation code stays the same. Temporality is chosen in SDK or exporter configuration, which is why operators can change it without involving developers or rebuilding the application.
A delta up-down counter only reports movements, so reconstructing the current level requires every point. One lost point corrupts the level permanently. Keeping these instruments cumulative avoids that fragility.
Not really. It limits how long the SDK remembers idle series, but active series are still created and still stored by the backend. Controlling attributes is the real remedy.
The total starts again from zero and the start time moves forward. Consumers that understand resets will treat the drop as a restart and continue counting correctly from the new value.
Yes. You can configure two metric readers in the SDK with different preferences, or send one flavor to a Collector and convert it for each destination with the conversion processors.
A delta needs a previous value to subtract from. The first cumulative point has no earlier baseline, so conversion processors usually treat it specially, often by using it only to initialise state.
Neither wins universally. Cumulative is more forgiving and fits Prometheus-style systems, while delta is leaner and fits short-lived workloads and delta-preferring vendors. The right answer depends on your backend, workload, and tolerance for lost data.
19Summary and Key Takeaways
Aggregation temporality answers a deceptively simple question: when the SDK reports a metric value, how far back in time does that value reach? In the cumulative answer, it reaches back to a fixed starting point, giving a resilient but memory-hungry stream. In the delta answer, it reaches back only to the previous report, giving a lean but fragile stream. The data model captures the choice through a temporality field and a pair of timestamps, the SDK lets you select it through a reader preference, and the Collector can translate between the two when needed.
The wise way to use this knowledge is to start from the destination, choose the flavor it expects, keep the pipeline consistent, convert only at the edge, control cardinality separately, and make sure every dashboard and alert query matches the flavor that is actually stored. Like the odometer and the trip meter, both flavors are honest. Trouble only starts when we forget which one we are reading.
Key Takeaways
- Temporality is about time windows — it says whether a value covers everything since a fixed start (cumulative) or only since the last report (delta).
- Timestamps reveal the flavor — a constant start time means cumulative, a moving start time that meets the previous end time means delta, and a jump in start time signals a reset.
- Only some metrics have it — sums, histograms, and exponential histograms carry a temporality, while gauges do not.
- Cumulative is forgiving, delta is lean — cumulative survives lost reports but keeps state for every series, while delta bounds memory but loses data permanently when points go missing.
- The destination usually decides — Prometheus-style systems expect cumulative, while some vendors prefer delta, so always check the backend’s documentation first.
- Conversion has a cost — Collector processors can translate between flavors, but they need per-series state, ordered delivery, and stable instances.
- Queries must match the data — use rates and increases for cumulative data and simple sums for delta data, and never treat delta as a cure for high cardinality.