What it does
Filter context is the set of filters in force when an expression is evaluated — everything the visual, slicers, page filters and relationships have applied. Row context is the "current row" that exists while a calculated column or an iterator function is walking a table. CALCULATE is the function that modifies filter context, and it's also the function that turns row context into filter context.
Key facts
- CALCULATE evaluates an expression in a modified filter context. If a filter argument touches columns already in the filter context, it overwrites those filters. If it touches columns that aren't, it adds them.
- Wrap a filter argument in KEEPFILTERS to add rather than replace.
- Boolean filter arguments have rules: they can reference columns from a single table only, can't reference measures, and can't contain a nested CALCULATE. Since the September 2021 Desktop release they also can't use functions that scan or return a table unless those are passed to an aggregation function.
- Filter modifier functions are REMOVEFILTERS, ALL / ALLEXCEPT / ALLNOBLANKROW, KEEPFILTERS, USERELATIONSHIP and CROSSFILTER. Where your tool supports REMOVEFILTERS, prefer it over ALL for clearing filters.
- Multiple filter arguments combine with AND. Use
&&and||inside a single argument for finer control. - CALCULATE used with no filter arguments does one specific job: it transitions row context to filter context. That's context transition.
- Referencing a measure inside an iterator triggers context transition implicitly, because a measure reference is wrapped in an invisible CALCULATE.
- CALCULATETABLE is the same function for expressions that return a table.
When to use / skip
There's no skipping this one — it's the concept that everything else in DAX sits on top of. Until someone understands that a measure re-evaluates under whatever filters each cell implies, and that CALCULATE rewrites those filters rather than adding to them, every DAX problem looks like a mystery. The practical test is whether they can explain why CALCULATE([Sales], 'Date'[Year] = 2025) returns 2025 sales in a visual already sliced to 2024. If they can, the rest is detail.
Configuration decisions
- Whether filter removal uses REMOVEFILTERS or the older ALL family, and that the team picks one and sticks to it.
- Whether ranking and comparison measures use KEEPFILTERS to respect existing slicers, or deliberately override them — this is a business rules decision, not a technical one.
- Where role-playing date relationships are handled: duplicate date tables with active relationships, or one table with inactive relationships and USERELATIONSHIP in the measures.
- Whether context transition is used deliberately in iterators, or avoided by restructuring the calculation.
Gotchas
- Context transition inside an iterator over a large table is the single most common cause of a slow measure. Every row triggers a fresh filter context.
SUMX(Sales, [Some Measure])over millions of rows will not end well. - People write
CALCULATE([Sales], 'Date'[Year] = 2025)expecting an extra filter and get a replacement. The slicer selection vanishes and nobody can see why. - Context transition also applies existing row values as filters, which means a measure inside an iterator over a table with duplicate rows can produce results people find genuinely surprising.
- EARLIER still appears in older code to reach outer row context. Variables do the same job more legibly, and there's rarely a reason to write EARLIER in a new model.
- A calculated column has row context but no filter context from the report — it's evaluated at refresh. Writing a "current selection" calculation as a calculated column never works and the error message doesn't say so.
Consultant notes
- Spend the training budget here rather than on function reference. A team that understands evaluation context can look up the rest; a team that doesn't will produce wrong numbers confidently.
- When a measure gives an unexpected number, the first question is always "what's the filter context in that cell", not "what's wrong with the formula". Teach the debugging order.
- Watch for iterators over fact tables in code review. It's the highest-yield thing to look for and it's usually visible at a glance.
- Be careful describing this to clients as "advanced DAX". It isn't advanced, it's foundational, and framing it as advanced gives people permission to skip it.
Sticky note: if a number looks wrong in one cell and right in another, start with filter context before touching the formula.