Row Context

Power BI documentation.

Row Context

Row context is the environment in which DAX evaluates one row at a time.

Unlike filter context, which determines which rows are visible, row context determines which row is currently being evaluated.

Row context is automatically created in calculated columns and iterator functions such as SUMX() and AVERAGEX().

Understanding row context is essential before learning CALCULATE() and context transition.


What Is Row Context?

Row context means DAX has access to the values from the current row.

Imagine the following table:

ProductQuantityUnit Price
Tire A550
Tire B375
Tire C840

If we create this calculated column:

Sales Amount =
FactSales[Quantity] *
FactSales[Unit Price]

Power BI evaluates every row individually.

Result:

ProductQuantityUnit PriceSales Amount
Tire A550250
Tire B375225
Tire C840320

Each calculation only uses values from the current row.


Calculated Columns Automatically Have Row Context

Every calculated column receives row context automatically.

Example:

Full Name =
Customer[First Name]
    & " "
    & Customer[Last Name]

For every customer, DAX reads the values from that specific row.

No filtering is required.


Measures Do NOT Have Row Context

Measures are evaluated using filter context, not row context.

Example:

Total Sales =
SUM(FactSales[SalesAmount])

The measure never knows which individual row it is on.

Instead, it evaluates all rows that remain after filtering.

This is one of the biggest differences between calculated columns and measures.


Row Context vs Filter Context

Although they sound similar, they serve different purposes.

Row ContextFilter Context
Evaluates one row at a timeFilters visible rows
Used by calculated columnsUsed by measures
Created automatically for each rowCreated by visuals, slicers, relationships, and filters
Reads values from the current rowDetermines which rows are included in calculations

Understanding the difference between these two concepts is fundamental to writing effective DAX.


Iterator Functions Create Row Context

Some DAX functions create their own row context.

These are known as iterator functions because they evaluate one row at a time.

Common iterators include:

  • SUMX()
  • AVERAGEX()
  • COUNTX()
  • MINX()
  • MAXX()

Example:

Total Sales =
SUMX(
    FactSales,
    FactSales[Quantity] *
    FactSales[Unit Price]
)

SUMX() works as follows:

Read Row 1

↓

Calculate
Quantity × Unit Price

↓

Read Row 2

↓

Calculate

↓

Read Row 3

↓

...

↓

Add all results together

Unlike SUM(), SUMX() evaluates an expression for every row before returning the final result.


Row context allows DAX to retrieve related values from another table.

Example model:

DimProduct
     |
     |
FactSales

Calculated column:

Category =
RELATED(DimProduct[Category])

Power BI reads the current FactSales row.

It then follows the relationship to DimProduct and returns the matching category.

Without row context, DAX would not know which product to retrieve.


Multiple Row Contexts

Iterator functions can create nested row contexts.

Example:

SUMX(
    FactSales,
    FactSales[Quantity] *
    FactSales[Unit Price]
)

For every row in FactSales:

  • Read Quantity
  • Read Unit Price
  • Multiply them together

After every row has been evaluated, the results are added together.

This is why iterator functions are generally more flexible than simple aggregation functions.


Business Example

Suppose a company stores:

ProductQuantityUnit Price
Tire A550
Tire B375
Tire C840

Using:

SUM(FactSales[SalesAmount])

requires a stored SalesAmount column.

Using:

SUMX(
    FactSales,
    FactSales[Quantity] *
    FactSales[Unit Price]
)

calculates the sales amount for every row dynamically.

This avoids storing an additional column while producing the same result.


When Row Context Exists

Row context is automatically created in:

  • Calculated columns
  • Iterator functions (SUMX, AVERAGEX, etc.)
  • Some nested DAX expressions

Measures do not automatically create row context.

This distinction is one of the most important concepts in DAX.


Context Transition

One of the most powerful features of DAX is context transition.

Context transition occurs when CALCULATE() converts a row context into a filter context.

This allows DAX to evaluate measures using values from the current row.

Without context transition, many advanced calculations would not be possible.


Why Context Transition Matters

Consider two calculated columns on DimCustomer:

No Transition =
SUM(FactSales[SalesAmount])

With Transition =
CALCULATE(SUM(FactSales[SalesAmount]))

A calculated column only has row context, and row context doesn't filter anything. So No Transition sees all of FactSales and returns the same grand total on every customer row.

With Transition wraps the same expression in CALCULATE(), which converts the current customer row into a filter. That filter flows across the relationship to FactSales, so each row returns that customer's own total.

Anatomy of context transition

DimCustomer[No Transition] = SUM(FactSales[SalesAmount])

DimCustomer[With Transition] = CALCULATE(SUM(FactSales[SalesAmount]))

CustomerNo TransitionWith Transition
Alice$1,500$500
Bob1$1,500$600
Chen$1,500$400

Inside CALCULATE, on Bob's row

1row context: Bob's row
↓
2filter: DimCustomer[Customer] = "Bob"
FactSales rowCustomerSalesAmount
1Alice$300
2Bob3$500
3Alice$200
4Chen$400
5Bob3$100

✓$600

1

Row context — a calculated column is evaluated once per row, so DAX knows it's on Bob's row. But row context doesn't filter anything: SUM() alone still sees all of FactSales and returns $1,500 on every row.

2

Transition — CALCULATE() turns the current row into a real filter: every column of that row becomes an equality filter on DimCustomer.

3

Propagation — that filter flows across the DimCustomer → FactSales relationship like any slicer would, leaving only Bob's 2 sales rows.

✓

Result — $600, Bob's own total. Referencing a measure such as [Total Sales] gives the same result without writing CALCULATE, because every measure reference is implicitly wrapped in one.

Measure References Do This Automatically

Every measure reference is implicitly wrapped in CALCULATE(). So this column returns the same per-customer totals as With Transition, with no CALCULATE() written:

Customer Sales =
[Total Sales]

Watch Out on Fact Tables

That implicit transition causes a classic mistake in calculated columns on a fact table:

-- Returns about 100% on every row, not a percent of total
Sales Percentage =
DIVIDE(
    FactSales[SalesAmount],
    [Total Sales]
)

Context transition filters FactSales down to the current sales row itself, so [Total Sales] returns that row's own amount. To divide by the table-wide total, use SUM() directly, which sees the whole table because there's no transition:

Sales Percentage =
DIVIDE(
    FactSales[SalesAmount],
    SUM(FactSales[SalesAmount])
)

Row Context vs Filter Context

Understanding when each context exists makes DAX much easier to understand.

FeatureRow ContextFilter Context
Created by Calculated Columns✅❌
Created by Measures❌✅
Created by Iterator Functions✅❌
Created by Report Filters❌✅
Created by Slicers❌✅
Modified by CALCULATE()➜ Converted✅

Although both contexts affect calculations, they solve different problems.


Common Beginner Mistakes

Many new Power BI developers confuse row context and filter context.

Common mistakes include:

  • Expecting measures to know the current row.
  • Using calculated columns for dynamic calculations.
  • Forgetting that iterator functions create row context.
  • Assuming SUM() behaves like SUMX().
  • Using RELATED() without a valid relationship.

Learning to recognize the active context makes debugging DAX much easier.


Best Practices

When working with row context:

  • Use calculated columns only for permanent attributes.
  • Use iterator functions when calculations require row-by-row evaluation.
  • Prefer measures for report calculations.
  • Understand whether your formula is executing in row context or filter context.
  • Keep calculations simple and reusable.

As your models grow, understanding context becomes far more important than memorizing DAX functions.


Summary

Row context evaluates one row at a time.

It is automatically created by:

  • Calculated columns
  • Iterator functions such as SUMX() and AVERAGEX()

Unlike filter context, row context does not determine which rows are visible. Instead, it provides access to the values in the current row.

Understanding both row context and filter context is the key to mastering DAX.


Next Steps

Now that you understand both contexts, you're ready to learn the most important DAX function:

Wrapped a column reference in CALCULATE() inside FILTER() and got a "True/False expression" error? Row context already gives direct column access — see that error explained.