FetchXML vs OData in Dataverse
Two query languages for Dataverse — what each does, performance and capability differences, and when to choose which.
Dataverse exposes its data through two distinct query languages: FetchXML (the older, Dataverse-native XML format) and OData (the standard REST-style query syntax used by most modern API consumers). Both can return the same underlying data; choosing the right one depends on the use case.
FetchXML.
FetchXML is Microsoft's XML-based query language for Dataverse. Used by:
- Advanced Find in the Dynamics 365 UI — what users see when building filtered views.
- Views stored in Dataverse — view definitions are FetchXML under the hood.
- Plug-ins doing complex queries via the SDK.
- Power Automate Dataverse "List rows" action can use FetchXML for advanced filtering.
- SSRS reports historically (now Power BI replaces SSRS).
Strengths:
- Complex queries — group-by, aggregate, hierarchical filtering with nested unions, complex join logic. More expressive than OData for analytical queries.
- Native to Dataverse — uses Dataverse-specific concepts like Link-Entity, Filter expressions, Order-By.
- Aggregations — count, sum, avg, min, max within a single query.
- Distinct — explicit DISTINCT support.
Weaknesses:
- Verbose XML — substantial markup for non-trivial queries.
- Dataverse-specific — doesn't translate to other systems.
- Documentation outside Microsoft's official sites is sparser.
- Limited 5000-record default page — extends with paging.
OData (Web API).
OData is the standard REST query syntax exposed by Dataverse's Web API (the /api/data/v9.x/ endpoint). Used by:
- Modern integrations — anything calling Dataverse from external systems.
- Power Automate flows — most common pattern.
- Custom JavaScript on forms (
Xrm.WebApi). - Power BI direct query to Dataverse.
- Mobile apps and SDKs.
Strengths:
- Standard syntax —
$filter,$select,$expand,$orderby,$top,$skipare familiar to anyone with OData experience. - Concise — URL-encoded query parameters; no XML.
- HTTP-native — works directly from REST clients, browsers, Postman.
- Documented broadly — OData standard documentation plus Dataverse-specific extensions.
- Modern toolchain — most SDKs and HTTP libraries support it natively.
Weaknesses:
- Less expressive for complex analytics — aggregations supported but more limited than FetchXML.
- Some Dataverse-specific operations are awkward in OData (e.g. complex link-entity joins).
- Filter expression syntax — quite expressive but doesn't support every FetchXML pattern.
Choosing.
Use FetchXML when:
- You're working with advanced-find or views (the platform uses FetchXML there).
- The query is highly analytical — group-by, aggregates, complex joins.
- You're inside a plug-in or other Dataverse SDK context.
Use OData when:
- Calling Dataverse from an external system.
- Writing a Power Automate flow's "List rows" action with simple filtering.
- Writing JavaScript on a form to fetch related records.
- Building a Power BI direct-query dataset.
- Anything modern and HTTP-driven.
Conversion. The Dataverse SDK can convert FetchXML to OData and vice versa for many patterns, but not all. Some advanced FetchXML patterns don't translate to OData; some OData patterns don't translate efficiently to FetchXML.
Performance. For equivalent queries, FetchXML and OData both compile to the same underlying SQL. Performance differences are typically negligible. Both honour Dataverse's indexes and security filters identically.
The Dataverse Query Designer. Several community tools (XrmToolBox plug-ins, "FetchXML Builder", "OData Query Designer") let you build queries visually and emit either format. Useful when you know the data but aren't fluent in either syntax.
Mixing approaches in one solution. A non-trivial integration might use both:
- The flow's main filter is OData (simpler, in Power Automate's Dataverse action).
- A complex secondary query uses FetchXML (passed to "List rows" with a Fetch XML Query parameter).
Both can be used side by side without conflict.
Common pitfalls.
- Hand-writing complex FetchXML without the tools — error-prone XML.
- OData $expand without $select — fetches all expanded fields, blowing up payload size.
- Filtering on calculated columns — neither query language indexes calculated columns efficiently. Use rollup or stored values.
- No paging on bulk queries — OData and FetchXML both default to 5000-record pages; explicit paging is required for larger sets.
Operational reality. Most modern Dataverse integration work uses OData. FetchXML remains relevant for analytical work, view-based queries, and SDK-level customisation. Pick deliberately per use case; don't fight the tool.
Related guides
- Azure API Management in front of DataverseHow API Management acts as a façade for Dynamics 365 APIs — rate limiting, authentication, transformation, observability, and developer portal — and why it matters at scale.
- Batch operations in the Dataverse Web APIHow to make multiple Dataverse Web API calls in one HTTP round-trip — $batch requests, change sets, and the performance gains at scale.
- Microsoft Graph and DataverseHow Microsoft Graph connects Microsoft 365 data to Dynamics 365 — Graph connectors, indexing Dataverse content, and the Copilot enablement story.
- B2C authentication with Dynamics 365 — Entra External ID and beyondHow to authenticate external customers and partners against Dynamics 365 — Entra External ID (formerly Azure AD B2C), Power Pages authentication, and the patterns for B2C identity in CRM and ERP.
- Entra External ID for customer accessHow Microsoft Entra External ID provides customer-grade identity for Power Pages portals and external Dynamics 365 access — sign-up flows, branding, social identity, and the migration from Azure AD B2C.