DAX (Data Analysis Expressions) is the formula language that powers every calculation in Power BI. While the UI lets you drag and drop fields, the real intelligence — YoY growth, running totals, dynamic rankings, KPI status — all comes from well-crafted DAX measures.
This guide is a copy-paste-ready reference library of the 25 DAX measures I use on almost every client project. Each measure includes a clean implementation, an explanation of what it does, and notes on where to use it.
Store all your measures in a dedicated Measures Table. Right-click in the Fields pane → Enter Data → create a blank table called _Measures. This keeps your model organised and makes every measure easy to find.
Category 1 — Core Revenue Measures (1–5)
These five measures are the foundation of almost every sales or financial dashboard. Build these first — everything else references them.
Measure 1 — Total Revenue
Total Revenue =
SUMX(
FactSales,
FactSales[Quantity] * FactSales[UnitPrice]
)
Why SUMX instead of SUM? SUMX iterates row by row and multiplies before summing — giving you the correct result even when discounts or currency conversions apply per row. SUM of a pre-calculated column works too, but SUMX is more flexible and avoids redundant calculated columns.
Measure 2 — Total Cost (COGS)
Total Cost =
SUMX(
FactSales,
FactSales[Quantity] * RELATED(DimProduct[UnitCost])
)
RELATED() fetches the unit cost from the related DimProduct table for each row in FactSales. This works because of the many-to-one relationship between FactSales and DimProduct.
Measure 3 — Gross Profit
Gross Profit =
[Total Revenue] - [Total Cost]
Measure 4 — Gross Margin %
Gross Margin % =
DIVIDE(
[Gross Profit],
[Total Revenue],
0
)
The / operator throws a divide-by-zero error when the denominator is blank or zero. DIVIDE(numerator, denominator, alternateResult) handles this gracefully — returning 0, BLANK(), or any value you choose. This is one of the most important DAX habits to build early.
Measure 5 — Average Order Value
Average Order Value =
DIVIDE(
[Total Revenue],
DISTINCTCOUNT(FactSales[OrderID]),
0
)
Category 2 — Time Intelligence (6–12)
Time intelligence is where DAX truly shines. These measures require a proper Date dimension table marked as a Date Table in Power BI (right-click the date table → Mark as date table).
Measure 6 — Revenue MTD
Revenue MTD =
TOTALMTD(
[Total Revenue],
DimDate[Date]
)
Returns the cumulative revenue from the start of the current month to the currently selected date. Use this in KPI cards to show month-to-date performance.
Measure 7 — Revenue QTD
Revenue QTD =
TOTALQTD(
[Total Revenue],
DimDate[Date]
)
Measure 8 — Revenue YTD
Revenue YTD =
TOTALYTD(
[Total Revenue],
DimDate[Date],
"31 Mar" -- Optional: fiscal year end date (remove for calendar year)
)
The third argument lets you define a custom fiscal year end. "31 Mar" means the fiscal year runs April–March (common in India). Remove it entirely for a standard January–December year.
Measure 9 — Revenue Last Year (LY)
Revenue LY =
CALCULATE(
[Total Revenue],
SAMEPERIODLASTYEAR(DimDate[Date])
)
Measure 10 — Revenue YoY Growth %
Revenue YoY % =
DIVIDE(
[Total Revenue] - [Revenue LY],
[Revenue LY],
BLANK()
)
Returns BLANK() instead of 0 when there is no prior-year data — this prevents misleading 0% growth from appearing in charts when a period simply has no comparison.
Measure 11 — Revenue vs Target
Revenue vs Target =
[Total Revenue] - [Sales Target]
Revenue vs Target % =
DIVIDE(
[Revenue vs Target],
[Sales Target],
0
)
Measure 12 — Previous Month Revenue
Revenue Previous Month =
CALCULATE(
[Total Revenue],
PREVIOUSMONTH(DimDate[Date])
)
Revenue MoM % =
DIVIDE(
[Total Revenue] - [Revenue Previous Month],
[Revenue Previous Month],
BLANK()
)
Category 3 — Running Totals (13–14)
Measure 13 — Running Total Revenue
Running Total Revenue =
CALCULATE(
[Total Revenue],
FILTER(
ALLSELECTED(DimDate[Date]),
DimDate[Date] <= MAX(DimDate[Date])
)
)
ALLSELECTED respects the user's date slicer selection while still accumulating values up to each date point. This is the correct running total pattern — not ALL(), which would ignore slicers entirely.
Measure 14 — Running Total % of Grand Total
Running Total % =
DIVIDE(
[Running Total Revenue],
CALCULATE([Total Revenue], ALLSELECTED(DimDate[Date])),
0
)
Category 4 — Rankings (15–17)
Measure 15 — Product Rank by Revenue
Product Rank =
RANKX(
ALLSELECTED(DimProduct[ProductName]),
[Total Revenue],
,
DESC,
DENSE
)
DENSE ranking means no gaps in rank numbers (1, 2, 3 — not 1, 2, 4 when there's a tie). ALLSELECTED ensures the rank updates correctly when the user applies slicers.
Measure 16 — Top N Filter
Top N Revenue =
VAR N = SELECTEDVALUE(TopNTable[N], 10)
VAR Rank = [Product Rank]
RETURN
IF(Rank <= N, [Total Revenue], BLANK())
Create a disconnected TopNTable with values like {5, 10, 20} and a slicer on it. This measure then dynamically filters to show only the top N products — without any hardcoded number.
Measure 17 — Customer Rank by Revenue
Customer Rank =
RANKX(
ALLSELECTED(DimCustomer[CustomerName]),
[Total Revenue],
,
DESC,
DENSE
)
Category 5 — Share & Ratio Measures (18–20)
Measure 18 — % of Total Sales
% of Total Sales =
DIVIDE(
[Total Revenue],
CALCULATE([Total Revenue], ALL(DimProduct)),
0
)
ALL(DimProduct) removes any product filter, so the denominator is always the grand total — regardless of which product is in context. This gives each product its true percentage share.
Measure 19 — % of Category Sales
% of Category Sales =
DIVIDE(
[Total Revenue],
CALCULATE(
[Total Revenue],
ALLEXCEPT(DimProduct, DimProduct[Category])
),
0
)
ALLEXCEPT removes all filters on DimProduct except Category — so the denominator is the category total. Each product shows its share within its own category.
Measure 20 — Transaction Count
Transaction Count =
COUNTROWS(FactSales)
Unique Customers =
DISTINCTCOUNT(FactSales[CustomerID])
Unique Products Sold =
DISTINCTCOUNT(FactSales[ProductID])
Category 6 — KPI & Conditional Logic (21–23)
Measure 21 — KPI Status (RAG)
KPI Status =
VAR Achievement = [Revenue vs Target %]
RETURN
SWITCH(
TRUE(),
Achievement >= 0, "🟢 On Track",
Achievement >= -0.10, "🟡 At Risk",
"🔴 Behind"
)
-- Colour version for conditional formatting
KPI Colour =
VAR Achievement = [Revenue vs Target %]
RETURN
SWITCH(
TRUE(),
Achievement >= 0, "#10B981", -- green
Achievement >= -0.10, "#F59E0B", -- amber
"#EF4444" -- red
)
Use KPI Status in a table or matrix to show text labels. Use KPI Colour as a dynamic field-value colour in card or table conditional formatting — creating a real RAG (Red-Amber-Green) dashboard.
Measure 22 — YoY Arrow Indicator
YoY Arrow =
VAR Growth = [Revenue YoY %]
RETURN
IF(
ISBLANK(Growth),
"—",
IF(Growth >= 0, "▲ ", "▼ ") &
FORMAT(ABS(Growth), "0.0%")
)
YoY Colour =
IF([Revenue YoY %] >= 0, "#10B981", "#EF4444")
Measure 23 — Dynamic KPI Card Title
Dynamic Title =
VAR SelectedYear = SELECTEDVALUE(DimDate[Year], "All Years")
VAR SelectedRegion= SELECTEDVALUE(DimRegion[RegionName], "All Regions")
RETURN
"Revenue — " & SelectedYear & " | " & SelectedRegion
Use this in a card visual's subtitle or title field. The text updates automatically as the user selects different slicers — eliminating the need for static titles that go out of date.
Category 7 — Utility Measures (24–25)
Measure 24 — Last Data Refresh Date
Last Sale Date =
"Data as of: " &
FORMAT(
MAX(FactSales[SaleDate]),
"DD MMM YYYY"
)
-- Alternative: show last refresh timestamp
Last Refreshed =
"Last refreshed: " &
FORMAT(
NOW(),
"DD MMM YYYY, hh:mm AM/PM"
)
Always add a "data as of" label to your dashboard so users know how fresh the data is. Place it in a small text card at the bottom of every report page.
Measure 25 — Selected Period Label
Selected Period =
VAR MinDate = FORMAT(MIN(DimDate[Date]), "DD MMM YYYY")
VAR MaxDate = FORMAT(MAX(DimDate[Date]), "DD MMM YYYY")
RETURN
IF(
MinDate = MaxDate,
MinDate,
MinDate & " to " & MaxDate
)
This measure reads the current date slicer selection and displays it as human-readable text — perfect for report headers, export filenames, or email subject lines when embedding reports.
Quick Reference — All 25 Measures
| # | Measure | Category | Key Function |
|---|---|---|---|
| 1 | Total Revenue | Core | SUMX |
| 2 | Total Cost | Core | SUMX + RELATED |
| 3 | Gross Profit | Core | Measure reference |
| 4 | Gross Margin % | Core | DIVIDE |
| 5 | Average Order Value | Core | DIVIDE + DISTINCTCOUNT |
| 6 | Revenue MTD | Time Intelligence | TOTALMTD |
| 7 | Revenue QTD | Time Intelligence | TOTALQTD |
| 8 | Revenue YTD | Time Intelligence | TOTALYTD |
| 9 | Revenue LY | Time Intelligence | SAMEPERIODLASTYEAR |
| 10 | Revenue YoY % | Time Intelligence | DIVIDE |
| 11 | Revenue vs Target | Time Intelligence | Measure reference |
| 12 | Revenue Previous Month | Time Intelligence | PREVIOUSMONTH |
| 13 | Running Total | Running Totals | CALCULATE + ALLSELECTED |
| 14 | Running Total % | Running Totals | DIVIDE + ALLSELECTED |
| 15 | Product Rank | Rankings | RANKX |
| 16 | Top N Filter | Rankings | RANKX + SELECTEDVALUE |
| 17 | Customer Rank | Rankings | RANKX |
| 18 | % of Total Sales | Share & Ratio | DIVIDE + ALL |
| 19 | % of Category Sales | Share & Ratio | DIVIDE + ALLEXCEPT |
| 20 | Transaction Count | Share & Ratio | COUNTROWS + DISTINCTCOUNT |
| 21 | KPI Status (RAG) | KPI & Conditional | SWITCH + TRUE() |
| 22 | YoY Arrow Indicator | KPI & Conditional | IF + FORMAT |
| 23 | Dynamic Title | KPI & Conditional | SELECTEDVALUE |
| 24 | Last Refresh Date | Utility | MAX + FORMAT |
| 25 | Selected Period Label | Utility | MIN + MAX + FORMAT |
Whenever a measure references another measure more than once, store it in a VAR. DAX evaluates variables only once — reusing the same measure expression directly causes it to be recalculated every time it appears, which significantly slows down large models.