A finance team at a mid-size distributor built a canvas app to flag overdue receivables. It worked perfectly in every demo. Then it went into production against a SharePoint list that had grown past 4,000 rows, and the “overdue balance” total the app displayed started coming in a little low every week, never wildly wrong, just quietly off by a shrinking or growing margin depending on how the underlying data happened to sort. Nobody got an error message. Nobody got a warning banner in the running app. The gallery rendered, the total summed, and the number was simply incomplete, because Power Apps had silently stopped looking at the data after the first 500 records.
That is the practical shape of a delegation problem, and it is one of the more consequential gaps between how canvas apps behave in the maker’s testing environment and how they behave once real data volume shows up. Power Apps delegation limits determine whether a formula gets pushed down to the data source, which processes it server-side and returns only the matching rows, or whether Power Apps has to pull a bounded chunk of records locally and evaluate the formula against that chunk alone. When delegation fails and the underlying table is larger than the configured limit, the app does not stop working. It keeps working, on a subset of the data, without saying so.
Why Power Apps delegation limits fail silently instead of crashing
A crash gets fixed immediately because someone notices. A silently truncated query gets fixed only when someone happens to reconcile the app’s output against the source system and finds a discrepancy, which in the receivables example took several weeks. For a technical team supporting Dynamics 365 or Power Platform deployments, this is the argument for treating delegation as an architecture decision made at design time, not a performance tweak applied after a slow gallery gets noticed.
The default data row limit in a canvas app is 500 records, adjustable up to a hard ceiling of 2,000 in the app’s Settings under General. Raising that number is a common instinct and a bad one to rely on as a fix, because it just moves the cliff edge further out rather than removing it; a table with 50,000 rows behaves identically whether the limit is set to 500 or 2,000; it only changes how much data has to grow before someone notices something is wrong. Microsoft’s own guidance for this reason recommends the opposite move during development: set the limit down to 1 in a test environment, which forces every non-delegable formula to reveal itself immediately with obviously wrong results, rather than leaving that discovery to production data volume.
What actually gets delegated, and what does not
Power Fx delegates a meaningful set of operations against supported data sources, including Dataverse, SharePoint Online, SQL Server, and Salesforce. Filter, Search, LookUp, and First all delegate, as do the standard comparison operators, And, Or, Not, StartsWith, EndsWith, and the core aggregates: Sum, Average, Min, Max, CountRows, and Count. Sort and SortByColumns delegate as well, with an important caveat covered below for SharePoint. The In operator delegates too, but only against a column on the base table; the moment a formula tests In against a related or lookup column, delegation breaks and the query falls back to local evaluation.

The non-delegable list is longer and easier to trip over than most makers expect. FirstN, Last, and LastN do not delegate. Neither does If, which means embedding conditional logic inside a Filter predicate is a common way a formula that looks delegable quietly is not. String manipulation functions including Left, Mid, Len, Lower, and Upper are non-delegable, along with Concatenate and the & operator, GroupBy, Ungroup, and type-casting functions like Text and Value. Collect and ClearCollect are non-delegable by nature, since they materialize data locally rather than querying it. A formula like Filter(Fruit, Mid(FruitName, 1, 1) = “A”) looks reasonable and reads cleanly, but because Mid cannot be pushed to the data source, it only ever evaluates against the first page of records pulled locally, meaning a record named “Pineapple” sitting past row 500 will never match a search for names starting with “P,” not because the logic is wrong, but because the function never sees that row.
SharePoint makes this worse than Dataverse does
Anyone who has built canvas apps against both SharePoint lists and Dataverse tables has felt the difference in how forgiving each source is, and the gap is documented, not just anecdotal. SharePoint does not delegate relational comparison operators (less than, greater than, not-equal) on plain text fields at all, only equality. IsBlank does not delegate against text fields either, and the commonly suggested workaround, comparing to Blank() directly, does not behave identically for genuinely empty strings versus null values, which is a subtle correctness gap worth documenting in code review rather than discovering in production.
The bigger gap sits in SharePoint’s complex column types: Choice, Lookup, Person, Group, Task Outcome, Managed Metadata, and External Data. None of these support delegated sorting, so Sort or SortByColumns against a Choice or Person field will silently fall back to sorting only the locally retrieved page. StartsWith does not work against subfields of Choice or Lookup columns. Person and Group fields only delegate on their Email and DisplayName subfields, not on other properties. A set of SharePoint system fields, including ContentType, ModerationStatus, VersionNumber, and several path-related fields, do not delegate under any function at all. UpdateIf and RemoveIf against SharePoint are handled through a batching simulation bounded by the same 500/2,000 record limit rather than a true server-side delegated operation, which matters for any flow that bulk-updates list items from within the app rather than through Power Automate.
Dataverse does not eliminate delegation limits, but it closes most of these specific gaps: relational operators work against text columns, In delegates on base-table columns consistently, and sorting against lookup and choice columns behaves as makers expect. For any canvas app expected to scale past a few thousand records with complex filtering or sorting, that difference is a legitimate factor in the SharePoint-versus-Dataverse decision, not just a licensing or governance one.
Designing around it instead of hoping around it
The most reliable pattern is to push complexity toward the data source rather than the formula bar. Where a filter needs to test a derived value, calculated columns created in Dataverse (or, with more limitation, in SharePoint) let the comparison happen against a pre-computed, delegable field instead of a runtime string function the client has to evaluate locally. Where a search needs to match across multiple text fields, Search() itself delegates and is usually a better first attempt than a hand-built Filter with concatenated conditions, since it is one of the few functions built specifically to delegate substring matching.
For teams supporting these apps in production rather than just building them, the practical safeguard is process, not just formula discipline: run the app with the row limit forced to 1 during test cycles, review any gallery, dropdown, or KPI tile driven by a filter or sort against a table that could plausibly exceed a few hundred rows in production, and treat a yellow delegation warning triangle in Power Apps Studio as a defect ticket rather than a cosmetic nag to dismiss. The warning is not a suggestion about performance. It is Power Apps telling the maker, in the only language it has, that the number on screen may not represent all of the data.
We’ve walked enough Dynamics 365 and Power Platform clients through exactly this kind of discovery, usually during a post-go-live support engagement rather than a planned architecture review, to treat delegation as a first-week design conversation on every canvas app project involving a table that is expected to grow. It is a cheap conversation to have early and an expensive one to have after a finance report has been quietly wrong for a month.


