Home › Data Analytics › DirectQuery Not Supported: Fix With Composite Models
Intermediate 6 min · September 23, 2026

DirectQuery Not Supported: Fix With Composite Models

Keep DirectQuery tables for big fresh facts; set dimensions to Import or Dual, and move unsupported DAX into import tables..

N
Naren Founder & Principal Engineer

20+ years shipping production backend systems. Written from production experience, not tutorials.

Follow
✓ Production
production tested
September 27, 2026
last updated
2,085
articles · all by Naren
Before you start⏱ 15 min
  • ✓Power BI Desktop connected to a relational source
  • ✓A star-schema model you may rebuild as composite
  • ✓Access to Performance Analyzer and Model view
 ● Production Incident 🔎 Debug Guide
⚡Quick Answer
  • DirectQuery translates each visual into a native source query, so calculated tables, untranslatable Power Query steps, and some DAX patterns fail
  • Open Model view and move small dimensions to Import or Dual storage, keeping only large fresh facts in DirectQuery
  • Rewrite unsupported logic as measures (SUM-based over an imported date table) instead of stored computed tables
  • When translation cannot serve the pattern at all, fall back to full Import with scheduled refresh and trade freshness for reliability
✦ Definition~90s read
What is Power BI DirectQuery Not Supported for This Operation?

DirectQuery is a connectivity mode where the Power BI model stores metadata only — table shapes, relationships, and measure definitions — while every visual triggers native queries against the live source. Nothing is imported and nothing is refreshed on a schedule; freshness is total because each query runs now.

★
Import mode is photocopying the library into your office: fast to read, but frozen at copy time.

Composite mode extends this by letting each table choose Import, DirectQuery, or Dual storage in one model, mixing in-memory dimensions with live facts. Import remains the default full-featured mode: data copied into memory, full DAX support, refreshed on a timetable.

The limitation landscape follows from what each mode stores. Pure DirectQuery forbids calculated tables (no import pass to materialize them), restricts calculated columns on relational sources to single-row logic, requires Power Query steps to fold into native operations, withholds automatic date hierarchies, and skips service features like Quick Insights that need in-memory scans.

DAX itself is limited to functions transposable into native queries. Composite relaxes this per table — calculated tables become Import tables, dimensions escape translation — while cross-source relationships take on limited many-to-many behavior with their own constraints.

Choosing among the modes is a freshness-versus-expressiveness trade with performance attached. Import offers every feature at memory speed with scheduled staleness. DirectQuery offers live data at per-query latency with a restricted palette. Composite offers both, at the cost of design discipline: per-table modes to assign, cross-source joins to keep narrow, and two performance regimes to monitor.

The decision belongs in design docs with a reason attached, because each mode fails differently and only the chosen mode's failures get monitored.

Plain-English First

Import mode is photocopying the library into your office: fast to read, but frozen at copy time. DirectQuery is phoning the library with every question: always current, but you can only ask questions the librarian understands, and complex requests take a while. Composite mode keeps popular reference books photocopied on your desk while phoning in only the breaking-news pages.

You connect live to the warehouse, build the report of your dreams, and publish — then visuals start failing with not-supported errors. Calculated tables refuse to create. A clever Power Query step works in Desktop and dies in the service. Time intelligence crawls. The promise of always-fresh data collides with a long list of things DirectQuery simply cannot do.

DirectQuery is a translation engine, not a data engine. Every visual becomes a native query against your source, which means every DAX function, every transformation step, and every modeling construct must survive translation. Anything without a native equivalent — stored computed tables, untranslatable steps, exotic DAX — fails at query time, often far from the authoring moment that introduced it. The errors feel random because the cause and the symptom live in different layers.

The escape routes are composite models and deliberate import fallback. Composite mode lets each table choose its storage: Import for dimensions, DirectQuery for the giant fresh facts, Dual for shared lookups. When translation cannot serve a pattern at all, full Import with scheduled refresh trades freshness for the complete feature set. This article maps the unsupported list, teaches per-table storage design, and shows the fallback path that ends the incident.

What DirectQuery Promises and What It Forbids

DirectQuery keeps no data — only metadata describing tables, columns, and relationships. When a visual renders, the engine generates a native query (usually SQL) against the live source, runs it, and displays the returned rows. The 1-GB model limit never applies because there is nothing to store, and every view reflects current source data without a refresh cycle. For giant fact tables and real-time dashboards, this is the only viable mode.

The price is the translation contract. DAX measures must convert into native query fragments the source understands; Power Query steps must fold into native operations; modeling constructs must have a query-time equivalent. Calculated tables have none — they materialize rows at refresh, and DirectQuery performs no import refresh to materialize into. Quick Insights vanishes for the same reason: it needs an in-memory scan the mode never builds. Automatic date and time hierarchies are unavailable, so drill-downs by year and month need an explicit date table.

Mode-proof design starts from these constraints rather than discovering them at publish. Favor simple SUM-based measures on DirectQuery facts, keep transformation steps foldable, and plan an explicit date table from day one. When a requirement needs an unsupported construct, that table becomes the composite-model Import candidate instead of a publish-day surprise. The mode works beautifully inside its contract and fails loudly outside it — both behaviors are features if you read the contract first.

ModeProofMeasure.daxDAX
1
2
3
-- Mode-proof measure: simple aggregation translates everywhere
Total Sales = SUM ( FactSales[SalesAmount] )
-- Prefer SUM-based measures on DirectQuery tables
📊 Production Insight
A team discovered calculated tables were unsupported at publish rehearsal, not design time. One composite remodel saved the launch. Rule: read the unsupported list before the first table, not the last week.
🎯 Key Takeaway
DirectQuery stores metadata only and translates visuals to native queries; anything without a query-time equivalent is unsupported.

The Usual Suspects: Tables, Columns, and Steps That Fail

Unsupported-operation errors cluster around three constructs. Calculated tables top the list: any DAX table expression meant to materialize rows has nowhere to land in a model that imports nothing. Calculated columns on DirectQuery tables face a narrower cell — expressions on relational sources are limited to single-row logic with no iterators like SUMX and no context modifiers like CALCULATE. Complex Power Query steps form the third cluster: an over-clever transformation with no native equivalent breaks the whole query, and multidimensional sources cannot use the editor at all.

Diagnosis is mechanical. The error or the failing visual names the table; open it in Power Query Editor and walk Applied Steps watching fold behavior, or inspect the DAX for table expressions and iterators sitting on DirectQuery tables. Reproduce against Import sample data if needed: constructs that work imported but fail live are translation casualties by definition. This comparison is the fastest classifier in the toolbox — same logic, two modes, different verdicts means the mode is the message.

Remediation follows the construct. Calculated tables become measures evaluated per visual, or Import tables inside a composite model. Unfoldable steps get simplified into native-friendly operations or pushed upstream into database views where the database optimizer owns them. Iterator-laden calculated columns become measures or move to Import tables. Each fix preserves the business logic while changing where it executes — the hallmark move of DirectQuery work is relocation, not reinvention.

PortableBuckets.daxDAX
1
2
3
4
5
6
-- Portable buckets: a measure replacing a calculated bucket table
Sales Band =
IF (
    SUM ( FactSales[SalesAmount] ) > 100000, "Large",
    IF ( SUM ( FactSales[SalesAmount] ) > 10000, "Medium", "Small" )
)
📊 Production Insight
A bucket table that worked on Import samples blocked a live launch for two days until it became a ten-line measure. Rule: same logic failing live but passing imported is always translation.
🎯 Key Takeaway
Compare Import versus live behavior to classify translation casualties, then relocate the logic to measures, views, or Import tables.

DAX That Translates and DAX That Does Not

DAX translation is the subtlest failure zone because partial success misleads. Simple aggregations — SUM, COUNT, AVERAGE over DirectQuery columns — translate into clean native SQL and fly. Time intelligence, complex iterators, and multi-table context juggling may translate into monstrous nested queries that time out, or refuse translation entirely. The visual shows numbers for small filters and dies on full-year views, which reads as flakiness while being perfectly deterministic query economics.

An explicit imported date table is the single highest-leverage fix. Mark it as the date table, keep it in Import storage even inside composite models, and aim all time functions at it. The engine then resolves date math locally against a tiny dimension and sends the source a simple date-range predicate instead of a calendar computation. YTD, parallel periods, and rolling averages that choked suddenly behave, because the hard part stopped traveling to the database.

Simplify remaining DAX toward translatable shapes. Replace iterator-over-relationship patterns with pre-aggregated Import tables where possible, break giant measures into VAR steps to isolate the offending fragment, and test each time function on production-scale data rather than samples. Performance Analyzer reveals the generated native query per visual — read it. When the SQL looks absurd, the DAX is asking absurdly; reshape the question until the SQL looks like something you would hand-write.

TranslatableYTD.daxDAX
1
2
3
4
5
6
-- Translatable YTD: SUM over an imported date table's year filter
Sales YTD =
CALCULATE (
    SUM ( FactSales[SalesAmount] ),
    DATESYTD ( DimDate[Date] )
)
📊 Production Insight
A YTD measure generated a seven-layer nested query that timed out every Monday. An imported date table reduced it to a date-range predicate. Rule: date math belongs in Import, not in translation.
🎯 Key Takeaway
Simple aggregations translate cleanly; aim time intelligence at an imported date table and read generated SQL in Performance Analyzer.

Composite Models: Per-Table Storage Done Right

Composite models end the all-or-nothing trap by assigning storage per table. Dimensions holding lookups become Import: slicers and group-bys resolve from memory with zero source chatter. Giant or real-time facts stay DirectQuery: visuals query current data without importing billions of rows. Shared dimensions become Dual, acting as Import when queried alone and joining DirectQuery facts efficiently from the same source. Calculated tables in composites are always Import, which quietly resolves the unsupported-table class of errors.

Cross-source relationships need respect. Tables from different sources relate as many-to-many with limited relationship behavior: DAX cannot fetch one-side values from the many side across the boundary, and groupings from Import tables get injected into native queries as materialized subqueries that can run slowly at scale. Keep cross-source joins narrow — low-cardinality keys, filtered grains — and push heavy integration upstream into one source or an Import staging table when the queries complain.

Design the mix deliberately and label it. A storage-mode standard — Import by default, DirectQuery only with a written freshness or volume reason, Dual for shared dimensions — stops mode sprawl. Review Model view's storage column each release like a dependency audit: every DirectQuery table should justify its per-query cost, and every Import table should justify its refresh weight. Models drift toward the mode of their first table; make that first choice conscious.

CompositeCategorySales.daxDAX
1
2
3
4
5
6
-- Composite-safe category total over Dual dimensions
Category Sales =
CALCULATE (
    SUM ( FactSales[SalesAmount] ),
    VALUES ( DimProduct[Category] )
)
📊 Production Insight
Setting five shared dimensions to Dual cut slicer queries to the source by 90% overnight. Rule: Dual dimensions are the cheapest performance win in composite modeling.
🎯 Key Takeaway
Import dimensions, DirectQuery giant facts, Dual shared lookups; keep cross-source joins narrow and every mode justified.

Performance Rules for Live Queries

Performance in DirectQuery is source economics plus chatter control. Each visual interaction emits native queries, so the source's indexes on join keys, filter columns, and date ranges decide the latency floor. Missing indexes turn every visual into a full scan billed per click. Partner with the DBA early: share the slowest native queries from Performance Analyzer, index what they touch, and re-measure. DirectQuery performance is a joint product of model and database, never the model alone.

Chatter control is the modeler's half. Imported dimensions eliminate lookup queries entirely; Dual dimensions halve them; careful visual design halves them again by filtering early and avoiding high-cardinality groupings that explode native result sets. Table and matrix visuals cap at 125 columns past 500 rows from DirectQuery sources, so wide tables paginate painfully — prefer focused measures with MIN, MAX, FIRST, or LAST aggregations for wide layouts. Every slicer is a query emitter; design pages so the first paint needs few of them.

Cache and capacity complete the picture. The service caches DirectQuery results where valid, but cache reuse shrinks when reports convert live connections into local models — workload and refresh-failure risk both rise. Monitor query volumes per report, set expectations with stakeholders that live data costs seconds where imported data costs milliseconds, and keep an Import fallback branch of critical pages for outage days. Freshness is a feature with a latency price; quote the price honestly.

⚠ Dimensions Do Not Belong in DirectQuery
Never leave small dimensions in DirectQuery by default. Every slicer click becomes a source query, and lookup traffic will swamp the database long before the fact queries do.
📊 Production Insight
Indexing three join keys cut a flagship page from nine seconds to under two. No DAX changed at all. Rule: when DirectQuery is slow, suspect the source first and the model second.
🎯 Key Takeaway
Index the source, import the dimensions, filter early, and quote live-data latency honestly to stakeholders.

The Import Fallback: Retreating Without Losing

Full Import fallback is the honorable retreat when translation cannot serve the pattern: unsupported source features, untranslatable core logic, or query economics no index can fix. Switching DirectQuery to Import is allowed (the reverse is not), so the path exists by design: import the data, regain calculated tables, full DAX, Quick Insights, and automatic date hierarchies, and pay with scheduled-refresh latency instead of per-query latency. For many operational reports, yesterday-fresh data at millisecond speed beats live data at nine seconds per click.

Migrate without forking logic. Keep measure definitions identical across the switch — SUM-based totals behave the same in both modes — so validation reduces to comparing totals between the old live report and the new imported one. Schedule refresh after source ETL completes, add the currency measures from refresh operations practice, and confirm Refresh history greens across several cycles before decommissioning the live version. Run both side by side during the transition week with a clear banner marking which is canonical.

Choose the mode per report, not per career. Real-time monitoring keeps DirectQuery with composite Import dimensions; monthly board packs go full Import; exploratory analysis prototypes composite and commits to whichever side the queries favor. Document the choice and its reason beside the model. The teams that suffer are not the ones on Import or DirectQuery but the ones that drifted into a mode without deciding — decide, write it down, and revisit yearly.

FallbackSafeTotal.daxDAX
1
2
3
-- Fallback-safe total: identical logic in Import and DirectQuery
Total Sales (fallback safe) = SUM ( FactSales[SalesAmount] )
-- Keep one measure definition so mode switches never fork logic
📊 Production Insight
A nine-second live page became a sub-second Import page with hourly refresh, and nobody missed the nine seconds of freshness. Rule: fallback is a design choice, not a defeat.
🎯 Key Takeaway
Switch DirectQuery to Import when translation fails; keep measure logic identical so validation is a totals comparison.
● Production incidentPOST-MORTEMseverity: high

The Publish-Day Outage Worn by an All-DirectQuery Model

Symptom
Calculated tables errored on refresh, time-intelligence visuals timed out, and every slicer click fired source queries with multi-second latency. The same report on Import sample data had been instant in development.
Assumption
The team assumed DirectQuery was Import with fresher data — same features, same DAX, same modeling. Nobody read the unsupported list, and the prototype's small data volume hid the per-query latency that production volumes would multiply.
Root cause
The entire model sat in DirectQuery, including small dimensions, a calculated bucket table, and YTD measures the source could not translate efficiently. Unsupported constructs failed outright while chatty dimension queries overloaded the source, combining into a report that was both broken and slow.
Fix
The model became composite: dimensions and the bucket table moved to Import, the sales fact stayed DirectQuery, and the YTD logic was rewritten against an imported date table. Slicer latency dropped from seconds to instant, the unsupported errors cleared, and a storage-mode standard (Import by default, DirectQuery by justification) entered the modeling guide.
Key lesson
  • DirectQuery is a different engine with a different contract, not a fresher Import. Every construct must survive translation, and the unsupported list is required reading before the first table.
  • Prototypes lie about DirectQuery performance. Small volumes mask per-query costs that production data multiplies; test with realistic volumes before committing.
  • Composite is the default answer, not the fallback. Per-table storage modes should be designed up front, with each DirectQuery table carrying a written reason.
Production debug guideFive checks that run in Model view, Power Query, Performance Analyzer, and the DAX query view.5 entries
Symptom · 01
Visuals fail or crawl across the whole report
→
Fix
In Power BI Desktop, open Model view and read the storage-mode indicator for each table. If everything shows DirectQuery including small dimensions and helper tables, you have found the design flaw. Change dimensions to Import or Dual (properties pane > Storage mode), keep only the large fresh facts in DirectQuery, and retest the failing visual.
Symptom · 02
One table's visuals fail with an unsupported-query error
→
Fix
Open the table in Power Query Editor (Home ribbon > Transform data) and step through Applied Steps while watching whether each step folds to the source. The step where folding breaks is the unsupported operation: simplify it into foldable operations, push it into a database view upstream, or move the table to Import storage in a composite model.
Symptom · 03
A measure works in Import but fails or crawls in DirectQuery
→
Fix
Start Performance Analyzer (View ribbon > Performance analyzer), refresh the visual, and expand its query timings to see the native query sent to the source. A missing or monstrous native query points at untranslatable DAX. Simplify the measure toward SUM-based logic over an imported date table and compare timings before and after.
Symptom · 04
You must prove replacement logic before remodeling
→
Fix
Open the DAX query view (View ribbon > DAX query view) and run the suspect measure with EVALUATE against a small filtered grain. If the logic needs a calculated table or a construct the source cannot express, rewrite it as pure measures first. Only proven-measure logic earns a place in the DirectQuery model.
Symptom · 05
You need proof the composite remodel holds before publishing
→
Fix
After remodeling, save a copy of the file, apply the new storage modes, and refresh every page with Performance Analyzer recording. Confirm no error pane appears, slicers respond quickly, and totals match the pre-change Import baseline. Publish only when the analyzer output and the totals both agree.
DirectQuery Failure Causes, Checks, and Fixes
Root CauseHow to ConfirmFixPrevention
Unsupported construct (calculated table, complex step)Error names the operation; visuals fail while Import copy worksConvert to measures or move the table to Import storageDesign review against the unsupported list before building
Power Query step that cannot foldNative-query preview breaks at one applied stepSimplify the step or push logic into a database viewVerify folding per step during development
DAX that will not translate efficientlySimple SUMs work; time-intelligence crawls or failsProvide an imported date table; simplify the DAXTest every time function on the live source early
Whole model in DirectQuery unnecessarilySlicers lag; source sees heavy lookup trafficSet dimensions to Import or Dual in a composite modelDefault new tables to Import; justify each DirectQuery one
⚙ Quick Reference
5 commands from this guide
FileCommand / CodePurpose
ModeProofMeasure.daxTotal Sales = SUM ( FactSales[SalesAmount] )What DirectQuery Promises and What It Forbids
PortableBuckets.daxSales Band =The Usual Suspects
TranslatableYTD.daxSales YTD =DAX That Translates and DAX That Does Not
CompositeCategorySales.daxCategory Sales =Composite Models
FallbackSafeTotal.daxTotal Sales (fallback safe) = SUM ( FactSales[SalesAmount] )The Import Fallback

Key takeaways

1
DirectQuery translates every visual to native queries, so only translatable DAX, steps, and constructs survive.
2
Calculated tables and Quick Insights are unsupported in pure DirectQuery; measures are the portable alternative.
3
Composite models assign Import, DirectQuery, or Dual storage per table for the best of both worlds.
4
Set dimensions to Import or Dual; reserve DirectQuery for large or real-time facts from one supported source.
5
Verify Power Query folding per step and test time intelligence on the live source early.
6
Fall back to full Import with scheduled refresh when translation cannot serve the pattern.

Common mistakes to avoid

5 patterns
×

Building Power Query steps that cannot fold to SQL

Symptom
The model validates in Desktop but visuals fail in the service with an unsupported-query error, because one transformation step has no native equivalent.
Fix
Open the failing query in Power Query Editor, identify the step that cannot fold (check the step's native-query preview), and either simplify it into foldable operations or move the logic into the database as a view. Re-apply until every step folds.
×

Adding calculated tables to a pure DirectQuery model

Symptom
The calculated table errors on creation or refresh, blocking the whole model over one helper table that felt harmless in Import mode.
Fix
Convert the logic to measures on the DirectQuery table or move the table to Import storage in a composite model. Measures evaluate per visual and translate cleanly where stored computed tables cannot.
×

Assuming every DAX time function translates to the source

Symptom
YTD and parallel-period measures fail or crawl on DirectQuery while simple SUMs fly, because the generated native query cannot express the date math efficiently.
Fix
Build an explicit date table (imported) with continuous dates and mark it as the date table, then write time intelligence against it. Test each time function in a visual before relying on it across the report.
×

Leaving every table in DirectQuery by default

Symptom
Slicers lag, each click fires source queries, and the database groans under lookup traffic that an imported dimension would have absorbed silently.
Fix
In Model view, set dimension tables to Import or Dual and keep only the large fresh facts in DirectQuery. Confirm the storage-mode column shows the intended mix before publishing.
×

Choosing DirectQuery for small static tables

Symptom
Reports pay per-query latency for data that never changes, while import would have served it from memory in milliseconds with zero source load.
Fix
Treat DirectQuery as the exception for large or real-time facts, and default new tables to Import. Document the reason beside every DirectQuery table so future editors do not copy the mode blindly.
INTERVIEW PREP · PRACTICE MODE

Interview Questions on This Topic

Q01JUNIOR
Compare Import and DirectQuery storage modes.
Q02JUNIOR
Why are calculated tables unsupported in pure DirectQuery?
Q03SENIOR
How do you assign storage modes in a composite model?
Q04SENIOR
How do you keep Power Query foldable for DirectQuery?
Q05SENIOR
A DirectQuery report keeps hitting unsupported operations. Walk through ...
Q01 of 05JUNIOR

Compare Import and DirectQuery storage modes.

ANSWER
Import loads a copy of the data into memory for fast flexible queries on a schedule; DirectQuery queries the live source per visual for always-current data. Import supports the full feature set including calculated tables and Quick Insights; DirectQuery restricts DAX, Power Query, and modeling features to what translates to native queries.
FAQ · 6 QUESTIONS

Frequently Asked Questions

01
What is the difference between Import and DirectQuery mode?
02
Why can't I add a calculated table in DirectQuery?
03
Can one model mix Import and DirectQuery tables?
04
What does Dual storage mode do?
05
Can I switch a model from DirectQuery to Import later?
06
How do I keep DirectQuery reports fast?
N
Naren Founder & Principal Engineer

20+ years shipping production backend systems. Written from production experience, not tutorials.

Follow
✓ Verified
production tested
September 27, 2026
last updated
2,085
articles · all by Naren
🔥

That's Power BI. Mark it forged?

6 min read · try the examples if you haven't

←
Previous
Power BI Data Source Credentials Not Refreshing on Service
5 / 7 · Power BI
Next
Power BI Column of Table Not Found — Broken Query Rename
→