Wicked Smart Data
LearnInsightsAboutContact
Sign InLet's Build
LearnInsightsAboutContact
Sign InLet's Build
Wicked Smart Data

Intelligence, automation, and expert execution — plus an elite library of free knowledge. We turn complexity into competitive advantage.

Start a conversation

Platform

  • Learning Paths
  • Insights
  • RSS Feed

Company

  • About
  • Contact
  • Work With Us

Legal

  • Privacy Policy
  • Terms of Service

© 2026 Wicked Smart Data. All rights reserved.

Intelligence · Automation · Advantage

All Insights
Power BI

DAX Formatting Best Practices: How to Write Readable, Maintainable Measures Using Indentation, Naming Conventions, and Comments

Unreadable DAX is a technical debt bomb waiting to go off. This lesson teaches you the indentation patterns, naming conventions, and commenting strategies that make your measures easy to debug, hand off, and extend — starting from first principles.

🌱 Foundation15 min readSep 16, 2026Updated Sep 16, 2026
DAX Formatting Best Practices: How to Write Readable, Maintainable Measures Using Indentation, Naming Conventions, and Comments
On this page
  • Introduction
  • Prerequisites
  • Why Formatting Matters More Than You Think
  • The Core Formatting Pattern: One Argument Per Line
  • Naming Conventions: Making Intent Self-Documenting
  • Measure Names
  • Variable Names
  • Table and Column References
  • Using VAR / RETURN to Structure Complex Logic
  • Writing Comments That Actually Help
  • Organizing Measures in Your Model
  • Hands-On Exercise
  • Common Mistakes & Troubleshooting
  • Summary & Next Steps
  • DAX Formatting Best Practices: How to Write Readable, Maintainable Measures Using Indentation, Naming Conventions, and Comments

    Introduction

    Picture this: you inherit a Power BI report from a colleague who left the company six months ago. You open the measure editor and find this:

    Metric=IF(ISBLANK(DIVIDE(CALCULATE(SUM(Sales[Revenue]),DATEYTD(TODAY(),'Calendar'[Date])),CALCULATE(SUM(Budget[Amount]),DATEYTD(TODAY(),'Calendar'[Date])))-1,0,DIVIDE(CALCULATE(SUM(Sales[Revenue]),DATEYTD(TODAY(),'Calendar'[Date])),CALCULATE(SUM(Budget[Amount]),DATEYTD(TODAY(),'Calendar'[Date])))-1)
    

    What does this measure do? Is it a sales ratio? A budget variance? A performance index? You genuinely cannot tell without spending 15 minutes untangling it — and that's assuming there are no bugs hidden in the nesting. This is the DAX formatting problem in its purest form: technically valid code that is practically unreadable.

    Good DAX formatting is not a cosmetic concern. It's an engineering discipline. When your measures are consistently structured, properly named, and thoughtfully commented, you can debug them faster, hand them off confidently, and extend them without accidentally breaking something. By the end of this lesson, you'll be able to write DAX that your future self — and your colleagues — will actually thank you for.

    What you'll learn:

    • How to use indentation and line breaks to reveal the logical structure of a measure
    • How to apply naming conventions to measures, variables, and tables that make their purpose immediately clear
    • How to write comments that add context without stating the obvious
    • How to use VAR / RETURN blocks to dramatically improve readability
    • How to apply consistent formatting patterns even to complex, nested measures

    Prerequisites

    This lesson assumes you're comfortable writing basic DAX measures in Power BI Desktop. You should understand what a measure is and how it differs from a calculated column — if you need a refresher, read DAX Fundamentals: When to Use Calculated Columns vs Measures in Power BI first. You should also have a general idea of how functions like SUM, CALCULATE, and IF work.


    Why Formatting Matters More Than You Think

    Let's get one myth out of the way: DAX does not care about whitespace. You can write a measure on one line or spread it across fifty lines, and Power BI will evaluate it identically. The formatting exists entirely for humans — for you, your teammates, and whoever inherits this report next year.

    There's a deeper reason formatting matters, though. The act of formatting your code forces you to understand it. When you manually indent a nested CALCULATE call and realize you need four closing parentheses at the end, you often catch a bug you'd otherwise have missed. Formatting is a thinking tool, not just a presentation tool.

    Key insight: Professional DAX developers spend as much time reading code as writing it. Formatting is an investment in that future reading — yours and everyone else's.

    Consider a realistic scenario: a finance analyst has built 40 measures for a P&L report. Six months later, the CFO wants to change how budget variance is calculated. If those 40 measures are unformatted blobs, every edit is a liability. If they're cleanly structured, the change takes an hour.


    The Core Formatting Pattern: One Argument Per Line

    The single most impactful habit you can build is placing each function argument on its own line, indented one level from its parent function. This applies everywhere: CALCULATE, IF, DIVIDE, SUMX, nested FILTER calls — everywhere.

    Here's a simple CALCULATE measure written flat:

    Revenue YTD = CALCULATE(SUM(Sales[Revenue]),DATESYTD('Calendar'[Date]))
    

    And here's the same measure formatted:

    Revenue YTD =
    CALCULATE(
        SUM( Sales[Revenue] ),
        DATESYTD( 'Calendar'[Date] )
    )
    

    That's it. Two arguments, two lines, one level of indentation. The function name sits on the line above its arguments, and the closing parenthesis returns to the indentation level of the function name. This is the foundational pattern — everything else builds on it.

    Now let's look at nesting. When one function is an argument to another, it gets indented further:

    High Value Revenue =
    CALCULATE(
        SUM( Sales[Revenue] ),
        FILTER(
            Sales,
            Sales[OrderAmount] > 10000
        )
    )
    

    Notice how FILTER is indented as an argument of CALCULATE, and its own arguments (Sales and the condition) are indented one further level. The closing parentheses stack up cleanly, each returning to the level of its opening function. Once you train your eye to read this pattern, the logical structure becomes immediately visible.

    Tip: Use the free tool DAX Formatter (daxformatter.com) to instantly apply consistent indentation to any measure you paste in. It's not perfect for every situation, but it handles 90% of the grunt work and is a great starting point when you're cleaning up inherited code.


    Naming Conventions: Making Intent Self-Documenting

    A well-named measure is half the documentation. A poorly named one forces anyone reading it to reverse-engineer your intent.

    Measure Names

    Measure names should be descriptive noun phrases that tell you what the number represents — not how it's calculated. Here are some patterns that work well in practice:

    Instead of this Use this
    Metric Revenue Variance %
    Calc1 Gross Margin $
    M_Sales Sales Amount
    BudVarYTD Budget Variance YTD
    x Customer Retention Rate

    Notice a few conventions in the "Use this" column:

    • Sentence case with spaces: Power BI renders measure names in UI elements — slicers, tooltips, axis labels. Natural-language names with spaces look professional and are self-labeling.
    • Unit suffix where relevant: Append $, %, #, or Qty when it removes ambiguity. Gross Margin is ambiguous — is it dollars or percent? Gross Margin $ and Gross Margin % are not.
    • Time period suffix for time intelligence measures: Revenue YTD, Revenue MTD, Revenue Prior Year makes a measure table scannable at a glance.

    Variable Names

    When you use VAR blocks — and you should be using them heavily, as we'll cover in the next section — your variable names follow a different convention. Since they live inside the measure and never surface in the UI, you can use camelCase or PascalCase without worrying about how they look to end users:

    Revenue vs Budget % =
    VAR CurrentRevenue = [Revenue YTD]
    VAR CurrentBudget = [Budget YTD]
    VAR VarianceAmount = CurrentRevenue - CurrentBudget
    RETURN
        DIVIDE( VarianceAmount, CurrentBudget )
    

    Each variable name reads like a sentence fragment that completes the thought "this stores the..." — CurrentRevenue stores the current revenue, VarianceAmount stores the variance amount. That clarity is the goal. If you'd like to go deeper on how variables improve both readability and performance, DAX Variables in Practice: Using VAR and RETURN to Simplify Complex Measures covers this in full detail.

    Table and Column References

    Always use the full TableName[ColumnName] reference form for columns inside your measures. Avoid the shorthand [ColumnName] alone — it works in some contexts but creates ambiguity in others and makes it harder to understand which table a column belongs to when you're reading the code cold.

    -- Avoid this:
    Total Orders = COUNT( [OrderID] )
    
    -- Prefer this:
    Total Orders = COUNT( Sales[OrderID] )
    

    Warning: The shorthand [ColumnName] without a table prefix only works safely when there's no ambiguity about row context. In iterator functions like SUMX or inside FILTER, always use the fully qualified reference to avoid subtle bugs that are very hard to trace.


    Using VAR / RETURN to Structure Complex Logic

    Variables are the single most powerful readability tool in DAX. They let you name intermediate calculations, avoid repeating expressions, and break a complex measure into a readable narrative. If you're writing a measure that has the same sub-expression appearing more than once, that's your immediate signal to extract it into a variable.

    Let's take that unreadable measure from the introduction and rebuild it properly:

    -- Before: unreadable wall of text
    Metric=IF(ISBLANK(DIVIDE(CALCULATE(SUM(Sales[Revenue]),DATEYTD(TODAY(),'Calendar'[Date])),CALCULATE(SUM(Budget[Amount]),DATEYTD(TODAY(),'Calendar'[Date])))-1,0,DIVIDE(CALCULATE(SUM(Sales[Revenue]),DATEYTD(TODAY(),'Calendar'[Date])),CALCULATE(SUM(Budget[Amount]),DATEYTD(TODAY(),'Calendar'[Date])))-1)
    
    -- After: readable, maintainable, debuggable
    Revenue vs Budget Variance % =
    
    VAR RevenueYTD =
        CALCULATE(
            SUM( Sales[Revenue] ),
            DATESYTD( 'Calendar'[Date] )
        )
    
    VAR BudgetYTD =
        CALCULATE(
            SUM( Budget[Amount] ),
            DATESYTD( 'Calendar'[Date] )
        )
    
    VAR VariancePct =
        DIVIDE( RevenueYTD, BudgetYTD ) - 1
    
    RETURN
        IF( ISBLANK( VariancePct ), 0, VariancePct )
    

    These two measures produce identical results. But the second one tells you at a glance: it calculates year-to-date revenue, year-to-date budget, computes the variance percentage, and returns 0 if the result is blank. That's a complete story, readable in under a minute.

    Notice the structure: each VAR gets its own block, with the assigned expression indented beneath it if it spans multiple lines. The RETURN keyword stands alone on its own line, signaling the transition from "building blocks" to "output." That's a convention worth adopting universally — it creates a visual checkpoint in every measure you write.

    Key insight: Variables in DAX are also evaluated only once, regardless of how many times you reference them. So extracting repeated sub-expressions into variables improves performance as well as readability — a genuine win on both fronts.


    Writing Comments That Actually Help

    DAX supports two comment styles:

    • Single-line comments: Begin with -- (double dash). Everything after the dashes on that line is ignored.
    • Block comments: Wrapped in /* ... */. Can span multiple lines.

    Both are invisible to the DAX engine. They exist purely for readers.

    The hardest skill in writing comments is knowing what not to comment. A comment that restates what the code already says is noise:

    -- Calculates the sum of revenue (don't write comments like this)
    VAR RevenueYTD = CALCULATE( SUM( Sales[Revenue] ), DATESYTD( 'Calendar'[Date] ) )
    

    The code already tells you it's calculating the sum of revenue. The comment adds nothing. Instead, write comments that explain why a decision was made, or what business rule the code encodes:

    -- Using DATESYTD with no second argument defaults the year-end to Dec 31.
    -- For fiscal year reports, pass the fiscal year end date as the second argument.
    VAR RevenueYTD =
        CALCULATE(
            SUM( Sales[Revenue] ),
            DATESYTD( 'Calendar'[Date] )
        )
    

    Now the comment is earning its place. It warns future readers about a non-obvious behavior and tells them what to change if business requirements shift.

    Here's a realistic example of a fully commented measure done well:

    /*
        Gross Margin % — Rolling 3-Month Average
        
        Business rule: Marketing uses a 3-month rolling average rather than
        point-in-time margin to smooth out seasonal promotions. This was
        aligned with the CFO in Q3 2024 planning cycle.
        
        Dependencies: Requires 'Calendar'[Date] to be marked as a date table.
    */
    
    Gross Margin % (3M Avg) =
    
    VAR GrossMarginCurrent =
        -- Margin in the current filter context
        DIVIDE(
            SUM( Sales[Revenue] ) - SUM( Sales[COGS] ),
            SUM( Sales[Revenue] )
        )
    
    VAR GrossMarginPrior2M =
        -- Expand context to prior 2 months and average across all 3
        CALCULATE(
            AVERAGEX(
                VALUES( 'Calendar'[MonthKey] ),
                DIVIDE(
                    SUM( Sales[Revenue] ) - SUM( Sales[COGS] ),
                    SUM( Sales[Revenue] )
                )
            ),
            DATESINPERIOD( 'Calendar'[Date], LASTDATE( 'Calendar'[Date] ), -3, MONTH )
        )
    
    RETURN
        -- Return 3M average; fall back to current-period margin if history unavailable
        IF( ISBLANK( GrossMarginPrior2M ), GrossMarginCurrent, GrossMarginPrior2M )
    

    The block comment at the top serves as a header: it names the measure, explains the business rule, and records a decision. The inline comments explain non-obvious technical choices. The variable names do the rest of the work.

    Tip: Make it a habit to include a brief header comment on any measure that encodes a business rule, uses a non-obvious technique, or was the subject of a stakeholder conversation. Future-you debugging at 5 PM on a Friday will be grateful.


    Organizing Measures in Your Model

    Formatting is not just about individual measures — it's also about how measures are organized in your model. A few conventions make a large model navigable:

    Use a dedicated measures table. Create an empty calculated table or a manually entered table named _Measures (the underscore sorts it to the top of the fields pane). Put all your measures in it. This keeps them separate from dimension and fact tables and makes them instantly findable.

    Group measures into display folders. In Power BI Desktop, you can assign a measure to a display folder in the Properties pane. Use folders like Revenue, Cost & Margin, YTD Comparisons, Budget Variance, and Customer Metrics to create a self-organizing hierarchy. When a report has 60+ measures, folders are the difference between navigable and chaotic.

    Prefix measure names by category in large models. In very large models where display folders aren't enough, some teams prefix measure names: REV_ for revenue measures, MARG_ for margin, CUST_ for customer metrics. This is a stylistic choice — use it only if it genuinely helps your team's workflow.

    Note: The naming prefix approach can conflict with the "natural language names" principle if measures surface directly in report tooltips. Weigh the tradeoff for your specific audience — internal analytics teams often prefer the prefix; executive dashboards usually benefit from cleaner names without it.


    Hands-On Exercise

    Let's put everything together. Below is a poorly formatted, poorly named measure. Your task is to reformat it from scratch using the conventions from this lesson.

    Starting point:

    x=IF(OR(ISBLANK(CALCULATE(SUM(Sales[Revenue]),FILTER(ALL(Sales),Sales[Region]=SELECTEDVALUE(Sales[Region])))),CALCULATE(SUM(Sales[Revenue]),FILTER(ALL(Sales),Sales[Region]=SELECTEDVALUE(Sales[Region])))<0),BLANK(),CALCULATE(SUM(Sales[Revenue]),FILTER(ALL(Sales),Sales[Region]=SELECTEDVALUE(Sales[Region]))))
    

    Step 1: Identify the repeated sub-expression. (Hint: CALCULATE(SUM(Sales[Revenue]),FILTER(ALL(Sales),Sales[Region]=SELECTEDVALUE(Sales[Region]))) appears three times.)

    Step 2: Extract it into a variable with a clear name.

    Step 3: Format the IF / OR logic using the one-argument-per-line pattern.

    Step 4: Add a one-line comment explaining the business rule (the measure returns BLANK when the selected region has zero or negative revenue).

    Step 5: Name the measure something descriptive — this is a filtered revenue figure for the selected region, with a blank guard for negative values.

    Here's one clean solution:

    -- Returns BLANK for regions with zero or negative revenue to suppress
    -- them from ranked visuals. Confirmed requirement from Sales Director.
    
    Region Revenue (Positive Only) =
    
    VAR SelectedRegionRevenue =
        CALCULATE(
            SUM( Sales[Revenue] ),
            FILTER(
                ALL( Sales ),
                Sales[Region] = SELECTEDVALUE( Sales[Region] )
            )
        )
    
    RETURN
        IF(
            OR(
                ISBLANK( SelectedRegionRevenue ),
                SelectedRegionRevenue < 0
            ),
            BLANK(),
            SelectedRegionRevenue
        )
    

    Three references became one. The logic is visible at a glance. The business rule is documented.


    Common Mistakes & Troubleshooting

    Mistake: Over-commenting the obvious. New DAX writers often comment every line to "be safe." This creates visual clutter that actually makes code harder to read. Reserve comments for business rules, non-obvious function behaviors, and architectural decisions.

    Mistake: Inconsistent indentation levels. Mixing 2-space and 4-space indentation within the same model is surprisingly disorienting. Pick a standard — most DAX developers use 4 spaces — and stick to it across every measure.

    Mistake: Generic variable names inside complex measures. Names like VAR Result or VAR Temp are only marginally better than no variables at all. Be specific: VAR BaselineSalesAmount, VAR FilteredCustomerCount.

    Mistake: Forgetting to update comments when the logic changes. A comment that no longer matches the code is worse than no comment — it actively misleads readers. When you update a measure's logic, update its comments in the same edit.

    Mistake: Putting all measures directly on fact or dimension tables. This makes the Fields pane harder to navigate and can obscure the purpose of individual measures. Use a dedicated measures table from the start.

    Warning: DAX Formatter and similar tools apply stylistic rules that don't always match every team's preferences. Treat auto-formatted output as a starting point, not a final product. Always review auto-formatted measures before committing them to a shared model.


    Summary & Next Steps

    Formatting is the first act of documentation. When you name a measure Revenue vs Budget Variance % instead of Metric, you've already answered the most important question anyone will ask about it. When you indent your CALCULATE arguments and extract repeated expressions into named variables, you make bugs visible and logic auditable. When you add a comment that explains why a business rule exists, you transfer context that would otherwise vanish when you leave the room.

    The patterns in this lesson are not optional polish for senior developers. They're foundational habits you should build from the very first measure you write. The cost of applying them is low — a few extra keystrokes and thirty seconds of thought. The cost of ignoring them compounds every time someone has to read your work.

    Here's a quick checklist to carry into your next Power BI session:

    • One function argument per line, indented four spaces
    • Descriptive measure names with unit suffixes where helpful
    • VAR / RETURN structure for any measure with more than one step
    • Fully qualified Table[Column] references
    • Comments that explain why, not what
    • All measures in a dedicated _Measures table with display folders

    From here, good next steps include exploring how formatting intersects with more advanced patterns. Since CALCULATE appears in virtually every complex measure, understanding Understanding DAX: CALCULATE and Filter Context deeply will help you format and reason about your most common construct. If you're building time intelligence measures — the kind that appear in almost every business report — Time Intelligence in DAX: YTD, MTD, Previous Period, and Rolling Averages will give you well-structured templates to work from. And when your measures grow in complexity toward financial reporting scenarios, Advanced DAX Patterns for Financial Reporting: Mastering P&L, Balance Sheet, and Budget Models shows how professional teams organize large measure libraries in production models.

    Write readable code. Your future self is counting on it.

    Work With Us

    From insight to implementation

    Reading is the start. When you're ready to build the data, automation, or AI systems behind it, our team turns strategy into shipped results.

    Let's Build

    DAX Mastery

    Previous

    DAX Query Optimization with VertiPaq Analyzer: Interpreting Column Cardinality, Relationship Materialization, and Data Model Compression to Eliminate Bottlenecks at Scale

    Related Insights

    Power BIFoundation

    Connecting Power BI to SQL Server: Writing Native Queries, Selecting Tables, and Managing Credentials for Reliable Data Loads

    19 min
    Power BIExpert

    Implementing Power BI Dataflows Gen2 with Azure Data Lake Storage Integration and Computed Entities to Build a Reusable Enterprise Transformation Layer

    29 min
    Power BIExpert

    DAX Query Optimization with VertiPaq Analyzer: Interpreting Column Cardinality, Relationship Materialization, and Data Model Compression to Eliminate Bottlenecks at Scale

    27 min

    On this page

    • Introduction
    • Prerequisites
    • Why Formatting Matters More Than You Think
    • The Core Formatting Pattern: One Argument Per Line
    • Naming Conventions: Making Intent Self-Documenting
    • Measure Names
    • Variable Names
    • Table and Column References
    • Using VAR / RETURN to Structure Complex Logic
    • Writing Comments That Actually Help
    • Organizing Measures in Your Model
    • Hands-On Exercise
    • Common Mistakes & Troubleshooting
    • Summary & Next Steps