The layout it produces
PasteKit formats DAX with a built-in DAX tokenizer and printer that follows the conventions popularised by SQLBI’s DAX Formatter, so the output will look familiar to anyone who has read their books or articles:
- a function call that fits on one line is written as
SUM ( Sales[Amount] ), with spaces inside the parentheses - a call that does not fit puts one argument per line, indented, with the closing parenthesis lined up under the function name
VARandRETURNeach start a new line, and the expression afterRETURNis indented- long chains of
&&and||break before the operator, so each condition reads as a line - measure definitions keep their
Name =header on the first line
Both measure and calculated-column definitions (Margin % = DIVIDE ( ... )) and full DAX queries starting with EVALUATE, DEFINE or containing ORDER BY are handled. Table references like 'Date'[Date] and column references like Sales[Amount] are kept exactly as written.
Function case and other settings
Function case has two choices. UPPER (the default) writes function names and keywords in capitals — CALCULATE, SAMEPERIODLASTYEAR, VAR, RETURN, EVALUATE — which is the near-universal convention in Power BI teams. As written leaves the casing you typed, for when you want only whitespace to change. Table, column and measure names are never re-cased in either mode, because they must match the model.
The toolbar indent sets how far arguments and RETURN bodies are indented, and the line width decides when a call is too long to stay on one line. Narrower widths produce the tall, one-argument-per-line style that many people find easiest to review in Tabular Editor or a pull request.
Shortcuts: Ctrl/Cmd+Enter to format, Ctrl/Cmd+Shift+C to copy back into Power BI Desktop, Ctrl/Cmd+K for the command palette. Ctrl/Cmd+Shift+M does not apply, since DAX has no minify mode here.
Forgiving by design
The parser is intentionally lenient. DAX has hundreds of functions and new ones arrive in Power BI updates, so anything the printer does not recognise is passed through token by token rather than rejected. Formatting therefore never drops, reorders or “corrects” your code. The only hard errors are the ones that make the expression impossible to read: an unclosed string, quoted table name or /* */ comment, or unbalanced parentheses and brackets. Each is reported with its line and column and a hint.
Comments in all three DAX styles (//, -- and /* */) are kept. This is not a semantic validator, so a misspelled column or a filter argument of the wrong type will format happily; Power BI will still tell you about those when you commit the measure.
Working with the rest of the Power BI stack? The Power Query formatter handles M code from the query editor.
Examples
Year-over-year measure with variables
Each VAR gets its own line, functions are upper-cased, and the RETURN expression is indented.
Sales YoY % = var cur=sum(Sales[Amount]) var prev=calculate(sum(Sales[Amount]),sameperiodlastyear('Date'[Date])) return if(isblank(prev),blank(),divide(cur-prev,prev))Sales YoY % =
VAR cur = SUM ( Sales[Amount] )
VAR prev =
CALCULATE ( SUM ( Sales[Amount] ), SAMEPERIODLASTYEAR ( 'Date'[Date] ) )
RETURN
IF ( ISBLANK ( prev ), BLANK (), DIVIDE ( cur - prev, prev ) )
SWITCH ( TRUE () ) banding
The SWITCH call is too long for one line, so every argument is placed on its own line.
Margin Band = var m=divide([Profit],[Revenue]) return switch(true(),m>=0.3,"High",m>=0.1,"Medium",isblank(m),blank(),"Low")Margin Band =
VAR m = DIVIDE ( [Profit], [Revenue] )
RETURN
SWITCH (
TRUE (),
m >= 0.3,
"High",
m >= 0.1,
"Medium",
ISBLANK ( m ),
BLANK (),
"Low"
)
DAX query, casing as written
With Function case set to As written, only whitespace changes; EVALUATE and ORDER BY each start a line.
evaluate summarizecolumns('Date'[Year],'Product'[Category],"Revenue",[Total Revenue],"Orders",countrows(Sales)) order by 'Date'[Year] descevaluate
summarizecolumns (
'Date'[Year],
'Product'[Category],
"Revenue",
[Total Revenue],
"Orders",
countrows ( Sales )
)
order by 'Date'[Year] desc
FILTER with a chain of conditions
Nested calls indent under CALCULATE; the && chain stays on one line because it fits the width.
Big Paid Orders = calculate(countrows(Orders),filter(Orders,Orders[Status]="Paid"&&Orders[Total]>1000&&Orders[Country]<>"SG"))Big Paid Orders =
CALCULATE (
COUNTROWS ( Orders ),
FILTER (
Orders,
Orders[Status] = "Paid" && Orders[Total] > 1000 && Orders[Country] <> "SG"
)
)
Common errors and how to fix them
| Error | Cause | Fix |
|---|---|---|
This '(' is never closed | A function call is missing its closing parenthesis, often at the very end of a long measure. | Add the matching ‘)’. Formatting the part that does parse with a narrower width makes the nesting easier to count. |
Unexpected ')' — there is no matching '(' before it | There is one closing parenthesis too many. | Remove the extra parenthesis at the reported column. |
This string is never closed | A text literal is missing its closing double quote. | Add the closing “. To put a quote inside a DAX string, double it (”"). |
This quoted table name is never closed | A table name in single quotes, such as ‘Date’, is missing its closing apostrophe. | Close the quote. An apostrophe inside a table name is written twice (‘’). |
Frequently asked questions
Is this the same as daxformatter.com?
It follows the same layout conventions but is an independent formatter that runs in your browser. Results are very close for typical measures.
Can I format a whole DAX query, not just a measure?
Yes. EVALUATE, DEFINE, MEASURE and ORDER BY are recognised, so queries from DAX Studio or Performance Analyzer format too.
Will it change my column or measure names?
No. Function case only affects functions and keywords; table, column and measure references are left exactly as written.
Does it check that my DAX is valid?
Only for unbalanced brackets and unclosed quotes. It has no access to your model, so references and types are not checked.