You already have the total revenue figure in your Power BI model and are asked to prepare a target for next year that is five percent higher. There are two ways to achieve this on the screen with identical results: adding a new column or creating a new measure that calls an existing measure. The figures are identical. The difference lies in when the calculation is executed, where the results are stored, and how much memory your model uses afterward.
Not two options, but five
Microsoft documentation notes five ways to add calculations to a Power BI report, and the differences are not a matter of preference.
| Aspect | Custom Column | Calculated Column | Measure | Visual Calculation |
|---|---|---|---|---|
| Language | M (Power Query) | DAX | DAX | DAX |
| Calculated When | Data Refresh | Data Refresh | On Demand | On Demand |
| Results Stored | Yes, in the table | Yes, in the model | No | No |
| Context | Row | Row | Filter | Visual |
| Changes with User Filters | No | No | Yes | Yes |
| Can Be Used As | Slicer, filter, row, column | Slicer, filter, row, column | Value in visuals and visual-level filters | Value in visuals |
The fifth option, calculated table, is used when you indeed want to store intermediate results as a table within the model.
Hidden Costs on the Screen
Calculated columns are computed once during data processing, and the results are stored in the model. This means that the column occupies RAM and continues to do so. The calculation time shifts to the refresh process rather than when the report is opened, which benefits the report reader. However, the memory cost never disappears.
The most common habit that bloats the model is breaking complex formulas into several intermediary columns. SQLBI refers to this method as useful during development but a bad habit in production, as each intermediary step is stored in memory. Measures work the opposite way: only the formula code is stored in the model, and the results are calculated when the query runs.
What Columns Cannot Do
There are calculations that do not have a column version at all, with percentage being the most common example. Margin per row can be calculated as a column, but the percentage margin for a group cannot be derived from the average of that column. The correct approach is the ratio of totals, not the total of ratios:
Gross Margin % = DIVIDE ( SUM ( Sales[GrossMargin] ), SUM ( Sales[SalesAmount] ) )
Once your calculation needs to operate on aggregated values rather than row by row, measures become the only way.
Two Naming Rules to Save Your Formulas Later
Microsoft provides two easy-to-remember recommendations precisely because they sound opposite:
- Columns should always be written out with their table name, for example,
Orders[Sales]. - Measures should never include the table name, just
[Profit].
The reasoning is practical. Each measure has a home table property that merely determines its location in the Data panel. If you ever move it, any formula referencing that measure with the table name will break, and you will need to edit them one by one. Conversely, writing columns fully prevents formulas from ambiguous references, and some functions like LOOKUPVALUE indeed require it.
VAR Replaces Intermediary Columns
If your reason for using intermediary columns is to keep the formula readable, DAX already has the answer. Variables declared with VAR are calculated at most once and can be reused in the RETURN section.
Microsoft's official example uses year-over-year sales growth. The version without variables calculates the previous year's expression twice. The version with one VAR returns the same result in about half the query time:
Sales YoY Growth % =
VAR SalesPriorYear =
CALCULATE([Sales], PARALLELPERIOD('Date'[Date], -12, MONTH))
RETURN
DIVIDE(([Sales] - SalesPriorYear), SalesPriorYear)
Variables are also always evaluated outside the filters applied in the RETURN section. Therefore, the EARLIER function, which used to be confusing, is generally no longer needed.
The Practical Rule in One Sentence
If the result needs to change when the user adjusts the slicer, it is a measure. If the result is used as a slicer, chart axis, or table row, then it is a column. The rest, including calling an old measure within a new measure, follows the same rules.
This method of calling a measure within another measure is also demonstrated in the class Building Data Dashboards with Power BI. If you prefer to see the explanation directly, there is a short clip demonstrating it.
Sources
- Microsoft Learn, "Use calculation options in Power BI Desktop", updated November 4, 2025. https://learn.microsoft.com/en-us/power-bi/transform-model/desktop-calculations-options
- Microsoft Learn, "Column and measure references in DAX". https://learn.microsoft.com/en-us/dax/best-practices/dax-column-measure-references
- Microsoft Learn, "Use variables to improve your DAX formulas". https://learn.microsoft.com/en-us/dax/best-practices/dax-variables
- SQLBI, "Calculated Columns and Measures in DAX". https://www.sqlbi.com/articles/calculated-columns-and-measures-in-dax/
- Microsoft Learn Indonesia, "Membuat pengukuran untuk analisis data di Power BI Desktop". https://learn.microsoft.com/id-id/power-bi/transform-model/desktop-measures