See your company like never before
Power BI deep-dives, migration playbooks, and data strategy for enterprise teams.


Join dozens of organizations who have moved to Beyond The Analytics. Book your personalized demo today
Use Claude AI to write, debug, and optimize DAX — prompt patterns, real examples, and where AI-generated DAX still needs analyst review.
Quick answer: Yes — Claude produces some of the cleanest DAX output of any AI model available today, but it is not infallible. You still need a developer who understands evaluation contexts, model relationships, and performance implications to review what comes back.
DAX is a notoriously difficult language to write correctly. Not because the syntax is complex — it is relatively compact — but because the mental model it requires is unlike any other language most developers encounter. Filter context and row context interact in ways that produce correct-looking measures that return wrong numbers. Context transition can silently change what a measure calculates depending on where you call it. And the performance difference between two logically equivalent expressions can be orders of magnitude.
So when developers ask whether an AI model can write production-quality DAX, the real question is: does it understand evaluation contexts, or does it just pattern-match syntax from training data?
Maxim Anatsko built DAXBench — a systematic evaluation of 70 different AI models on their ability to generate correct DAX. The results are revealing. Across all models tested, there were six times more syntax errors than semantic errors (360 versus 63). AI models generally understand the business logic — what you want to calculate — but trip on DAX-specific grammar that does not exist in SQL or Python. The function RANKX alone caused 40% of all failures, because models consistently forget about optional parameters or drop a comma.
Among all models tested, Claude Opus produced the cleanest, most consistent DAX output. That does not mean it is perfect. It means that when you provide adequate context about your data model, Claude is more likely to return a syntactically correct, well-structured measure than any other model currently available.
The practical takeaway: Claude is a powerful DAX drafting tool, not a replacement for a developer who understands the language. Treat every AI-generated measure the way you would treat a measure written by a junior developer — verify it against known results before deploying it.
Quick answer: The single most important thing you can do is include your data model schema — table names, column names, data types, relationships, and existing measures — in the prompt. Without this context, any AI model is guessing.
Most failed AI-generated DAX traces back to the same root cause: the model did not know enough about the semantic model to produce an accurate measure. Claude has a 1 million token context window, which means you can paste your entire model schema — hundreds of tables, thousands of columns, every existing measure — into a single conversation. This is a fundamental advantage over tools with smaller context limits.
Before asking Claude to write any measure, provide the context it needs:
Here is my Power BI semantic model:
Tables:
- Sales (OrderID, CustomerID, ProductID, OrderDate, Quantity, UnitPrice, DiscountPct)
- Customer (CustomerID, CustomerName, Segment, Region, FirstOrderDate)
- Product (ProductID, ProductName, Category, SubCategory, StandardCost)
- Date (Date, Year, Quarter, Month, MonthName, WeekNum, IsWeekend)
Relationships:
- Sales[CustomerID] → Customer[CustomerID] (many-to-one)
- Sales[ProductID] → Product[ProductID] (many-to-one)
- Sales[OrderDate] → Date[Date] (many-to-one)
Existing measures:
- Total Revenue = SUMX( Sales, Sales[Quantity] * Sales[UnitPrice] * (1 - Sales[DiscountPct]) )
- Total Cost = SUMX( Sales, Sales[Quantity] * RELATED( Product[StandardCost] ) )
Write a measure for year-over-year revenue growth percentage.
With this context, Claude returns a well-structured measure:
Revenue YoY % =
VAR CurrentRevenue = [Total Revenue]
VAR PriorYearRevenue =
CALCULATE(
[Total Revenue],
SAMEPERIODLASTYEAR( 'Date'[Date] )
)
RETURN
IF(
NOT ISBLANK( PriorYearRevenue ),
DIVIDE( CurrentRevenue - PriorYearRevenue, PriorYearRevenue )
)Notice what Claude does well here: it uses the existing [Total Revenue] measure instead of rewriting the aggregation, applies the VAR/RETURN pattern for readability, uses DIVIDE to avoid division-by-zero errors, and wraps the result in ISBLANK to suppress misleading percentages when prior-year data does not exist.
Same model as above. Our fiscal year starts April 1.
The Date table has a FiscalYear column (e.g., "FY2025" for Apr 2024 – Mar 2025).
Write a fiscal year-to-date running total for revenue.
Revenue FYTD =
VAR CurrentDate = MAX( 'Date'[Date] )
VAR FiscalYearStart =
IF(
MONTH( CurrentDate ) >= 4,
DATE( YEAR( CurrentDate ), 4, 1 ),
DATE( YEAR( CurrentDate ) - 1, 4, 1 )
)
RETURN
CALCULATE(
[Total Revenue],
'Date'[Date] >= FiscalYearStart
&& 'Date'[Date] <= CurrentDate,
ALL( 'Date' )
)This is a solid starting point. A developer reviewing it might consider whether DATESYTD with a custom year-end parameter (DATESYTD( 'Date'[Date], "3-31" )) would be cleaner and more compatible with other time intelligence functions. That is exactly the kind of review you should always perform — the AI gives you a working draft, and you refine it to match your model's conventions.
Same model. Write a measure that calculates the retention rate:
the percentage of customers from a given cohort month who placed
at least one order in a subsequent month. The visual will have
Cohort Month on rows and Months Since First Purchase on columns.
Cohort Retention % =
VAR CohortCustomers =
CALCULATETABLE(
DISTINCT( Sales[CustomerID] ),
ALLEXCEPT( Customer, Customer[FirstOrderDate] )
)
VAR CohortSize = COUNTROWS( CohortCustomers )
VAR RetainedCustomers =
COUNTROWS(
FILTER(
CohortCustomers,
NOT ISEMPTY(
CALCULATETABLE(
Sales,
ALLEXCEPT( 'Date', 'Date'[Year], 'Date'[Month] )
)
)
)
)
RETURN
DIVIDE( RetainedCustomers, CohortSize )This is where things get interesting. Claude produces a structurally sound cohort measure, but a senior developer would review the filter context carefully. Cohort retention patterns are among the most context-sensitive DAX measures you can write — the interaction between the visual's filter context and the ALLEXCEPT calls must be validated against real data. The logic is correct in isolation, but whether it produces the right numbers depends entirely on how your date table and customer table relate to the visual's axes.
Quick answer: Claude excels at CALCULATE with complex filter manipulation, time intelligence, iterator patterns, semi-additive measures, and RLS expressions — essentially any pattern where the developer's intent can be described clearly in natural language.
CALCULATE is the most important and most misused function in DAX. Claude handles its filter arguments well because the function follows logical rules that map cleanly to natural language descriptions.
Ask Claude for "revenue where product category is Electronics, ignoring any slicer selection on category," and you get:
Electronics Revenue (Ignore Slicer) =
CALCULATE(
[Total Revenue],
'Product'[Category] = "Electronics",
REMOVEFILTERS( 'Product'[Category] )
)This is correct. REMOVEFILTERS clears the external filter on category before the new filter is applied. Many developers would reach for ALL( 'Product'[Category] ) in the same position — both work, but REMOVEFILTERS makes the intent clearer.
For GCC enterprises, custom calendar requirements are common. Fiscal years that start in January, April, or July. Dual Gregorian-Hijri calendars for government reporting. 4-4-5 retail calendars.
Claude handles standard time intelligence patterns well. With the calendar-based time intelligence functions that entered preview in Power BI's September 2025 release, you can now define custom calendar structures directly in DAX. Claude can help generate the configuration for these new calendar-aware functions, though you should verify against the latest SQLBI documentation since these features are recent.
Iterators like SUMX and AVERAGEX require understanding the difference between row context and filter context. Claude handles the common patterns reliably:
Weighted Avg Unit Price =
VAR TotalQuantity = SUM( Sales[Quantity] )
RETURN
DIVIDE(
SUMX(
Sales,
Sales[Quantity] * Sales[UnitPrice]
),
TotalQuantity
)Balance sheet and inventory data require semi-additive measures — values that should not be summed over time. Claude produces the standard LASTNONBLANKVALUE pattern without prompting:
Current Inventory =
CALCULATE(
SUM( Inventory[UnitsOnHand] ),
LASTNONBLANK(
'Date'[Date],
CALCULATE( SUM( Inventory[UnitsOnHand] ) )
)
)The nested CALCULATE inside LASTNONBLANK is necessary for context transition — a subtlety that many developers miss manually and that Claude handles correctly.
Claude can generate RLS filter expressions from plain-language descriptions:
Our RLS requirement: Regional managers should only see data for
their assigned region. The mapping is in a RegionAccess table
with columns UserEmail and Region.
[Region] IN
SELECTCOLUMNS(
FILTER(
RegionAccess,
RegionAccess[UserEmail] = USERPRINCIPALNAME()
),
"Region", RegionAccess[Region]
)This is correct and follows the recommended pattern for dynamic RLS. Claude also correctly uses USERPRINCIPALNAME() rather than USERNAME() — the right choice for Power BI Service deployments. For a broader reference on the DAX functions Claude handles well, see our DAX functions reference guide.
Quick answer: Context transition surprises, performance on large tables, bidirectional relationship assumptions, and circular dependencies — these are the areas where AI-generated DAX most commonly needs correction.
Being honest about limitations is important. Claude writes structurally clean DAX, but there are patterns where any AI model will produce measures that need careful review.
Context transition — where a row context is automatically converted to a filter context by CALCULATE — is the single hardest concept in DAX. When a measure is called inside an iterator, CALCULATE implicitly wraps around it, triggering context transition. This can produce unexpected results when the developer did not intend for transition to occur.
Claude generally handles explicit CALCULATE correctly. Where it can struggle is in measures where context transition is implicit — for example, when a measure reference inside SUMX triggers a hidden CALCULATE. If the result looks wrong, check whether unintended context transition is changing the filter context mid-iteration.
AI-generated DAX is frequently correct but not optimal. The most common performance issue is using FILTER on large tables when a column filter or KEEPFILTERS would suffice.
Before (AI-generated, correct but slow):
High Value Revenue =
CALCULATE(
[Total Revenue],
FILTER(
Sales,
Sales[Quantity] * Sales[UnitPrice] > 1000
)
)After (optimized):
High Value Revenue =
CALCULATE(
[Total Revenue],
FILTER(
ALL( Sales[Quantity], Sales[UnitPrice] ),
Sales[Quantity] * Sales[UnitPrice] > 1000
)
)The difference: the first version iterates the entire Sales table row by row. The second version filters only the relevant columns, which is dramatically faster on tables with millions of rows. SQLBI's guidance is clear — filter columns, not tables. AI models do not always follow this principle because the row-level FILTER pattern is more common in training data.
Claude does not know your model's cross-filter direction unless you tell it. If you have bidirectional relationships — common in many-to-many bridge patterns — the AI may generate measures that assume single-direction filtering. Always specify relationship directions in your prompt when they matter.
DAX does not allow circular references between measures or calculated columns. Claude will occasionally generate a measure that references another measure which, through a chain of dependencies, references the original. These errors are caught at validation time, but they waste iteration cycles. The fix is simple: include your existing measure dependencies in the prompt so Claude can avoid the cycle.
Quick answer: The Model Context Protocol lets Claude interact directly with your Power BI semantic model — reading structure, running DAX queries, creating measures, and auditing existing formulas — turning it from a chat-based assistant into an integrated development tool.
This is where Claude's capabilities go beyond what any chat-based AI interaction can offer. Through MCP servers like Microsoft's Power BI Modeling MCP or Maxim Anatsko's MCP Engine, Claude can connect directly to your Power BI Desktop model and perform operations programmatically.
| Operation | Without MCP | With MCP |
|---|---|---|
| Read model schema | Copy-paste into chat | Automatic discovery |
| Create measures | Copy DAX from chat, paste into model | Claude writes directly to model |
| Test a measure | Run manually in DAX query view | Claude executes and reviews results |
| Audit existing measures | Export, paste into chat | Claude reads all measures in-place |
| Rename measures to convention | Manual, one at a time | Batch rename via natural language |
| Add measure descriptions | Manual, one at a time | Claude generates and applies descriptions |
This is where the 1 million token context window matters. A large enterprise semantic model might have 300 to 500 measures. With MCP, Claude can read every measure in your model, identify patterns that violate DAX best practices — missing VAR/RETURN, nested IF instead of SWITCH, FILTER on full tables — and propose optimizations across the entire model in a single session.
Consider a practical workflow: you ask Claude to "audit all measures in this model and flag any that use FILTER on a full table instead of filtering columns." Claude reads each measure through MCP, identifies the offending patterns, and generates optimized replacements. What would take a developer hours of manual review happens in a single conversation.
Other high-value MCP workflows:
The Microsoft Power BI Modeling MCP server supports both Power BI Desktop and Fabric semantic models. It provides 20+ tool groups covering tables, columns, measures, relationships, security roles, calculation groups, and DAX query execution. A --readonly mode is available for safe exploration of production models.
Need help setting up Claude for your team's DAX workflows? As an official Claude partner, Beyond The Analytics can onboard your team safely — from prompt libraries to governance policies. Book a consultation to get started.
Quick answer: Use Copilot for quick, in-context DAX queries while you are already working in Power BI. Use Claude for complex, multi-measure development sessions where you need deep reasoning, model-wide auditing, or custom prompt workflows.
This is not a competition — they serve different workflows. We covered Copilot's enterprise readiness requirements in detail previously. Here is how they compare specifically for DAX work:
| Capability | Power BI Copilot | Claude (with MCP) |
|---|---|---|
| DAX query generation | Yes — in DAX query view | Yes — via chat or MCP |
| Measure creation | No — queries only, not model measures | Yes — writes measures to model via MCP |
| Context awareness | Current model metadata (tables, columns, measures) | Full model via MCP or user-provided schema |
| Metadata limits | 500 tables, 10,000 columns, 5,000 measures max | 1 million token context — effectively unlimited |
| Explain existing DAX | Yes | Yes |
| Bulk operations | No | Yes — audit, rename, document across entire model |
| Custom prompt patterns | No — fixed interface | Yes — reusable prompt libraries |
| Licensing | Fabric capacity (F2+) required | Anthropic API or Claude subscription |
| Offline/local | No — requires Azure OpenAI backend | MCP server runs locally against PBI Desktop |
The most significant difference is scope. Copilot operates within a single DAX query view session — you ask for one query at a time. Claude with MCP operates across your entire semantic model. For a developer who needs to write one quick query to check a number, Copilot is faster. For a developer who needs to build, refactor, or audit dozens of measures, Claude with MCP is more capable.
Another practical difference: Copilot's metadata limits mean it may not fully understand very large models. If your semantic model has more than 500 tables or 5,000 measures, Copilot uses a reduced view of the metadata. Claude faces no such limit — you can load the entire model into context.
Based on DAXBench testing of 70 AI models, Claude Opus produces the cleanest and most consistent DAX output. However, "best" depends on your workflow. For integrated, in-editor suggestions while working in Power BI, Copilot is the most convenient option. For complex multi-measure sessions, model auditing, or bulk operations, Claude with MCP provides deeper capabilities. The key to quality DAX output from any AI model is providing complete schema context — table names, column names, relationships, and existing measures.
No. Claude is a productivity tool that accelerates DAX development, not a replacement for understanding the language. The DAXBench findings showed a 6:1 ratio of syntax errors to semantic errors across all AI models — meaning AI understands business intent but still makes grammatical mistakes in DAX. More critically, AI does not understand your specific model's performance characteristics, bidirectional relationship configurations, or the downstream impact of context transition. Every AI-generated measure should be reviewed by someone who understands DAX evaluation contexts.
Use an MCP (Model Context Protocol) server. Microsoft provides an official Power BI Modeling MCP server that connects Claude to Power BI Desktop or Fabric semantic models. The setup involves installing the MCP server, configuring it in your Claude client (Claude Desktop or Claude Code), and pointing it at your running Power BI Desktop instance. Once connected, Claude can read your model structure, create and modify measures, run DAX queries, and manage relationships — all through natural language.
Claude handles explicit filter context manipulation well — CALCULATE with filter arguments, REMOVEFILTERS, ALL, and KEEPFILTERS patterns are generally correct. Where any AI model struggles is with implicit context transition — the automatic wrapping of measures in CALCULATE when called inside iterators. If your measure involves complex interactions between row context and filter context, especially with iterator functions, always verify the results against known data before deploying.
It can be. AI models tend to favor correctness over performance, which means they sometimes use patterns like FILTER( TableName, ... ) on entire tables when filtering columns would be faster. The most common optimization gap is using FILTER on full tables instead of column pairs, followed by not leveraging KEEPFILTERS where appropriate. Always profile AI-generated measures with DAX Studio or Performance Analyzer on realistic data volumes — a measure that runs fine on 10,000 rows may be unacceptably slow on 10 million.
Microsoft Partner · Dubai
Your business intelligence partner for the GCC
Have a data challenge or a project in mind? Reach out and let's explore how we can help.
Clients we've worked with






