Measures
Claude.ai skill packages for authoring Power BI semantic models — TMDL, DAX measures, calculation groups, DAX UDFs, and a visual design system. Plain-text output ready to paste into Power BI Desktop or Tabular Editor.
npx -y skills add jonathan-pap/PowerBI-Claude-Design --skill measuresAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
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.
SKILL.md
12.9 KB, as published. Nobody here has run it
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 Discountsbeats$ 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 Analysisfolder - Group by business metric, not by function (
Key Metrics, notSUM 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])notTODAY()— 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 comparisonTarget 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