How to create a running total in DAX: step by step
A running total adds up values progressively over time: for example, sales from the start of the year up to each day. It is one of the most requested measures in a Power BI report, because it turns a plain column of values into an easy-to-read evolution line. With the right pattern in DAX, a running total takes just a few lines and works with any measure you already have. This guide shows how to create a running total in DAX, step by step and with a practical example.
Prerequisites
- A Power BI model with a fact table (for example
Vendas) and a calendar table (for exampleCalendário). - An active relationship between
Calendário[Data]and the date in theVendastable. - A base measure, for example
Total Vendas = SUM(Vendas[Valor]). - Basic knowledge of how to create measures in DAX.
Step 1: make sure you have a calendar table
A running total needs a continuous date column, with no gaps, so it can move forward in time. If you don't yet have a dedicated calendar table, create one with CALENDAR and relate it to your sales table.

Calendário =
CALENDAR(DATE(2023, 1, 1), DATE(2026, 12, 31))
Next, select the table and use the "Mark as date table" option, choosing the Data column. This step is what makes time calculations behave as expected.
Step 2: create the base measure
If it doesn't exist yet, create the measure you want to accumulate. Keep it simple, because the running total just reuses it inside a different filter context.
Total Vendas = SUM(Vendas[Valor])
Step 3: write the running total
Now for the main pattern. The idea is to sum [Total Vendas] for every date up to the date in the current context. We use CALCULATE to redefine the date filter and FILTER with ALLSELECTED to iterate over all the dates visible in the report.
Total Acumulado =
CALCULATE(
[Total Vendas],
FILTER(
ALLSELECTED('Calendário'[Data]),
'Calendário'[Data] <= MAX('Calendário'[Data])
)
)
Two details make it all work. MAX('Calendário'[Data]) returns the last date in the current context — that is, the date on that row of the visual. And ALLSELECTED ignores the row context but respects slicer filters, so the running total reacts to the user's filters without being limited to a single date.
Tip: if you replaceALLSELECTEDwithALL, the running total stops respecting slicers and always considers every date in the model.
Step 4 (optional): year-to-date with TOTALYTD
If what you need is the total since the beginning of the year (year-to-date), there is an even shorter shortcut with the TOTALYTD function:
Vendas YTD =
TOTALYTD([Total Vendas], 'Calendário'[Data])
The difference matters: Total Acumulado adds up everything from the start of the data, while Vendas YTD resets every 1 January. Choose the measure based on the business question you want to answer.
Check the result
Create a table or a line chart with Calendário[Data] (or the month) on the axis and add [Total Vendas] and [Total Acumulado] side by side. Then confirm three things:
- The
Total Acumuladonever goes down: it only rises or stays flat from one period to the next. - The value on the last date matches the grand total of
[Total Vendas]. - When you pick a year in a slicer, the running total adjusts to the selected period.
If the running total jumps to strange values, the most likely reason is that Calendário hasn't been marked as a date table, or the relationship to the sales table is missing.
Conclusion
With a single CALCULATE + FILTER + ALLSELECTED pattern you get a running total that respects the report filters, and with TOTALYTD you solve the specific case of the year-to-date total. From here it is worth trying variants: a running total by product category, a seven-day moving average, or a comparison with the same period last year. Which one will you need first in your next report?