| name | measures |
| description | Comprehensive guide to designing, naming, and implementing Power BI DAX measures across all business domains. Includes patterns for base aggregations, time intelligence, KPIs, semi-additive measures, and TMDL syntax for measure definitions in .tmdl files. |
| version | 2 |
Power BI DAX Measures โ Design Studio Guide
This guide teaches how to scaffold a complete measure layer for any Power BI semantic model. Use this when a user describes their reporting needs to generate production-ready DAX expressions with proper naming, folder structure, and TMDL syntax.
1. Naming Conventions & Prefixes
All measures use prefixes to signal their type.
| Prefix | Type | Example | formatString |
|---|
# | Count / Distinct Count | # Orders, # Customers | #,0 |
$ | Currency | $ Revenue, $ Cost | "$#,0.00" |
% | Ratio / Percentage | % Margin, % Growth | "0.00%" |
ฮ | Variance (Absolute) | ฮ Revenue, ฮ Headcount | "#,0" or "$#,0" |
ฮ% | Variance (Percent) | ฮ% Revenue, ฮ% Target | "0.00%" |
| (none) | Helper / Dimension | Days in Period, Current Month Num | varies |
Naming Principles
- Verbose over cryptic:
$ Revenue Net of Discounts beats $ Rev ND
- Avoid abbreviations except standard business terms (YTD, QTD, MTD, PY)
- Order variants left-to-right: base first, then comparisons
- โ
$ Revenue, $ Revenue PY, $ Revenue YTD
- โ
$ PY Revenue, $ YTD Revenue
2. Display Folder Structure
โโโ Key Metrics
โ โโโ Revenue & Profitability
โ โโโ Efficiency
โ โโโ Quality
โโโ Time Intelligence
โ โโโ Year-to-Date
โ โโโ Prior Year Comparisons
โ โโโ Period-over-Period
โโโ Budget vs Actual
โ โโโ Actual Measures
โ โโโ Budget Measures
โ โโโ Variance
โโโ Ratios & Rates
โโโ Drilling & Details
โโโ Helper Calculations
Rules:
- One or two levels deep โ avoid deeper nesting
- Align folders with report pages: a "Variance Analysis" page โ
Variance Analysis folder
- Group by business metric, not by function (
Key Metrics, not SUM Measures)
3. TMDL Wrapper
All generated TMDL uses createOrReplace targeting _measures.
Measures sit at 2 TABs, properties at 3 TABs, multi-line DAX body at 4 TABs:
createOrReplace
ref table _measures
/// Description of the measure
measure '$ Revenue' = SUM(Sales[Revenue])
formatString: "$#,0.00"
displayFolder: "Key Metrics\Revenue & Profitability"
The createOrReplace / ref table _measures header is omitted from the pattern
examples below for brevity โ always include it in generated output.
4. Base Measure Patterns
Pattern 1: Simple Sum / Count
DAX:
$ Revenue = SUM(Sales[Revenue])
# Orders = COUNTROWS(Sales)
TMDL:
/// Total revenue from all sales transactions
measure '$ Revenue' = SUM(Sales[Revenue])
formatString: "$#,0.00"
displayFolder: "Key Metrics\Revenue & Profitability"
/// Number of sales orders
measure '# Orders' = COUNTROWS(Sales)
formatString: "#,0"
displayFolder: "Key Metrics"
Pattern 2: SUMX for Row-Level Calculation
DAX:
$ Revenue = SUMX(Sales, Sales[Quantity] * Sales[Unit Price])
TMDL:
measure '$ Revenue' =
SUMX(Sales, Sales[Quantity] * Sales[Unit Price])
formatString: "$#,0.00"
displayFolder: "Key Metrics\Revenue & Profitability"
Pattern 3: Conditional Aggregation with CALCULATE + FILTER
DAX:
# High-Value Orders =
CALCULATE(
COUNTROWS(Sales),
Sales[Revenue] > 1000
)
TMDL:
measure '# High-Value Orders' =
CALCULATE(
COUNTROWS(Sales),
Sales[Revenue] > 1000
)
formatString: "#,0"
displayFolder: "Key Metrics"
Pattern 4: Distinct Count
DAX:
# Customers = DISTINCTCOUNT(Sales[CustomerID])
TMDL:
measure '# Customers' = DISTINCTCOUNT(Sales[CustomerID])
formatString: "#,0"
displayFolder: "Key Metrics"
Pattern 5: Average / Rate with DIVIDE
DAX:
$ Average Order Value =
DIVIDE(
SUM(Sales[Revenue]),
DISTINCTCOUNT(Sales[OrderID]),
0
)
TMDL:
measure '$ Average Order Value' =
DIVIDE(
SUM(Sales[Revenue]),
DISTINCTCOUNT(Sales[OrderID]),
0
)
formatString: "$#,0.00"
displayFolder: "Key Metrics\Efficiency"
5. Time Intelligence Patterns
Requires a marked Date table with a [Date] column and an active relationship to fact tables.
Pattern 1: Year-to-Date (YTD)
DAX:
$ Revenue YTD =
CALCULATE(
[$ Revenue],
DATESYTD(Date[Date])
)
TMDL:
measure '$ Revenue YTD' =
CALCULATE(
[$ Revenue],
DATESYTD(Date[Date])
)
formatString: "$#,0.00"
displayFolder: "Time Intelligence\Year-to-Date"
Pattern 2: Quarter-to-Date (QTD)
DAX:
$ Revenue QTD =
CALCULATE(
[$ Revenue],
DATESQTD(Date[Date])
)
TMDL:
measure '$ Revenue QTD' =
CALCULATE(
[$ Revenue],
DATESQTD(Date[Date])
)
formatString: "$#,0.00"
displayFolder: "Time Intelligence\Quarter-to-Date"
Pattern 3: Month-to-Date (MTD)
DAX:
$ Revenue MTD =
CALCULATE(
[$ Revenue],
DATESMTD(Date[Date])
)
TMDL:
measure '$ Revenue MTD' =
CALCULATE(
[$ Revenue],
DATESMTD(Date[Date])
)
formatString: "$#,0.00"
displayFolder: "Time Intelligence\Month-to-Date"
Pattern 4: Prior Year (PY)
DAX:
$ Revenue PY =
CALCULATE(
[$ Revenue],
SAMEPERIODLASTYEAR(Date[Date])
)
TMDL:
measure '$ Revenue PY' =
CALCULATE(
[$ Revenue],
SAMEPERIODLASTYEAR(Date[Date])
)
formatString: "$#,0.00"
displayFolder: "Time Intelligence\Prior Year Comparisons"
Pattern 5: Prior Year YTD
DAX:
$ Revenue PY YTD =
CALCULATE(
[$ Revenue],
SAMEPERIODLASTYEAR(DATESYTD(Date[Date]))
)
TMDL:
measure '$ Revenue PY YTD' =
CALCULATE(
[$ Revenue],
SAMEPERIODLASTYEAR(DATESYTD(Date[Date]))
)
formatString: "$#,0.00"
displayFolder: "Time Intelligence\Prior Year Comparisons"
Pattern 6: Rolling N Months
DAX:
$ Revenue L12M =
CALCULATE(
[$ Revenue],
DATESINPERIOD(Date[Date], LASTDATE(Date[Date]), -12, MONTH)
)
TMDL:
measure '$ Revenue L12M' =
CALCULATE(
[$ Revenue],
DATESINPERIOD(Date[Date], LASTDATE(Date[Date]), -12, MONTH)
)
formatString: "$#,0.00"
displayFolder: "Time Intelligence\Period-over-Period"
Use LASTDATE(Date[Date]) not TODAY() โ LASTDATE respects the visual's date filter.
6. KPI Measures โ Variance, Status, Targets
Pattern 1: Absolute Variance
DAX:
ฮ Revenue vs Target = [$ Revenue] - [Target Revenue]
TMDL:
measure 'ฮ Revenue vs Target' = [$ Revenue] - [Target Revenue]
formatString: "$#,0.00"
displayFolder: "Budget vs Actual\Variance"
Pattern 2: Variance as Percentage
DAX:
ฮ% Revenue vs Target =
DIVIDE(
[$ Revenue] - [Target Revenue],
[Target Revenue],
0
)
TMDL:
measure 'ฮ% Revenue vs Target' =
DIVIDE(
[$ Revenue] - [Target Revenue],
[Target Revenue],
0
)
formatString: "0.00%"
displayFolder: "Budget vs Actual\Variance"
Pattern 3: Status Flag (โ1 / 0 / 1)
Returns 1 (above target), 0 (no data), โ1 (below target) โ drives conditional formatting or SVG icons.
DAX:
Status Revenue =
IF(
ISBLANK([$ Revenue]),
0,
IF([$ Revenue] >= [Target Revenue], 1, -1)
)
TMDL:
measure 'Status Revenue' =
IF(
ISBLANK([$ Revenue]),
0,
IF([$ Revenue] >= [Target Revenue], 1, -1)
)
formatString: "0"
displayFolder: "Budget vs Actual"
Pattern 4: Target / Budget Measure
DAX:
Target Revenue = SUM(Budget[TargetRevenue])
TMDL:
measure 'Target Revenue' = SUM(Budget[TargetRevenue])
formatString: "$#,0.00"
displayFolder: "Budget vs Actual\Budget Measures"
7. Semi-Additive Measures
Semi-additive measures must not be summed across time. Use LASTNONBLANK or LASTDATE.
Pattern 1: Period-End Balance (LASTNONBLANK)
Use case: Headcount, inventory, account balance at end of period.
DAX:
# Headcount EOP =
CALCULATE(
SUM(Headcount[Employees]),
LASTNONBLANK(Date[Date], CALCULATE(SUM(Headcount[Employees])))
)
TMDL:
measure '# Headcount EOP' =
CALCULATE(
SUM(Headcount[Employees]),
LASTNONBLANK(Date[Date], CALCULATE(SUM(Headcount[Employees])))
)
formatString: "#,0"
displayFolder: "Key Metrics"
Pattern 2: Period-End Balance (LASTDATE)
DAX:
$ Account Balance EOD =
CALCULATE(
SUM(GL[Balance]),
LASTDATE(Date[Date])
)
TMDL:
measure '$ Account Balance EOD' =
CALCULATE(
SUM(GL[Balance]),
LASTDATE(Date[Date])
)
formatString: "$#,0.00"
displayFolder: "Key Metrics"
Pattern 3: Average of Semi-Additive
DAX:
$ Average Daily Balance =
AVERAGEX(
VALUES(Date[Date]),
[$ Account Balance EOD]
)
TMDL:
measure '$ Average Daily Balance' =
AVERAGEX(
VALUES(Date[Date]),
[$ Account Balance EOD]
)
formatString: "$#,0.00"
displayFolder: "Key Metrics"
8. Error Handling
DIVIDE (preferred over /)
Always use DIVIDE(numerator, denominator, alternateResult) โ returns alternateResult (default BLANK()) instead of an error when denominator is zero.
% Margin =
DIVIDE(
SUM(Sales[Profit]),
SUM(Sales[Revenue]),
0
)
IFERROR
Catches any error in an expression:
% Utilization =
IFERROR(
DIVIDE(SUM(Hours[Billable]), SUM(Hours[Total]), BLANK()),
BLANK()
)
VAR + ISBLANK guard
Prevents downstream errors when a dependency measure is blank:
$ Revenue vs Target =
VAR _actual = [$ Revenue]
VAR _target = [Target Revenue]
RETURN
IF(
ISBLANK(_target),
BLANK(),
_actual - _target
)
9. formatString Quick Reference
| Pattern | Displays as | Use for |
|---|
"$#,0.00" | $1,234.56 | USD currency |
"โฌ#,0.00" | โฌ1,234.56 | EUR currency |
"#,0" | 1,235 | Whole number counts |
"0.0%" | 12.3% | Percentages (1 decimal) |
"0.00%" | 12.35% | Percentages (2 decimal) |
"#,0,,"M" | 1.2M | Compact millions |
"#,0,"K" | 1.2K | Compact thousands |
10. Measure Assembly โ Requirements to TMDL
When a user describes reporting needs, follow this process:
Example: "Track quarterly sales with prior-year comparison and variance to quota."
Step 1 โ Extract metrics:
$ Revenue โ base sum
$ Revenue PY โ prior year comparison
Target Quota โ budget/target
ฮ Revenue vs Quota โ absolute variance
ฮ% Revenue vs Quota โ percent variance
Step 2 โ Assign folders:
Key Metrics\Revenue & Profitability โ $ Revenue
Budget vs Actual\Budget Measures โ Target Quota
Budget vs Actual\Variance โ ฮ Revenue vs Quota, ฮ% Revenue vs Quota
Time Intelligence\Prior Year โ $ Revenue PY
Step 3 โ Generate TMDL:
createOrReplace
ref table _measures
measure '$ Revenue' = SUM(Sales[Amount])
formatString: "$#,0.00"
displayFolder: "Key Metrics\Revenue & Profitability"
measure 'Target Quota' = SUM(Budget[QuotaAmount])
formatString: "$#,0.00"
displayFolder: "Budget vs Actual\Budget Measures"
measure '$ Revenue PY' =
CALCULATE(
[$ Revenue],
SAMEPERIODLASTYEAR(Date[Date])
)
formatString: "$#,0.00"
displayFolder: "Time Intelligence\Prior Year Comparisons"
measure 'ฮ Revenue vs Quota' = [$ Revenue] - [Target Quota]
formatString: "$#,0.00"
displayFolder: "Budget vs Actual\Variance"
measure 'ฮ% Revenue vs Quota' =
DIVIDE([ฮ Revenue vs Quota], [Target Quota], 0)
formatString: "0.00%"
displayFolder: "Budget vs Actual\Variance"
11. Key Properties Reference
| Property | Purpose | Example |
|---|
formatString | Display format in visuals | "$#,0.00", "0.00%", "#,0" |
displayFolder | Group in Field List | "Key Metrics\Revenue" |
description | Tooltip in Field List | "Cumulative revenue YTD" |
isHidden | Hide from Field List | isHidden (for helper measures) |
Related References
- tmdl-standards/SKILL.md โ TMDL syntax ground rules: indentation, createOrReplace wrapper, property order
- calc-groups/SKILL.md โ When to replace individual Time Intelligence measures with a calc group
- dax-udf/SKILL.md โ When to extract repeated measure logic into a reusable typed function
- svg-measures/SKILL.md โ Wrapping scalar measure output in SVG strings for visual KPI display
Version: 2.0
Last Updated: 2026-05-02