Canvas apps at platform scale: push work to Dataverse
Canvas is wonderful until one screen becomes a distributed system: nested galleries, OnStart fan-out, and business rules living in Power Fx because it was faster.
Microsoft's own performance reference architectures push a clear direction. Move heavy work toward Dataverse and keep screens focused.

Figure 1. Optimize canvas apps with platform-aligned architecture. Source: Microsoft Learn: optimize canvas app performance.
I have inherited canvas apps that felt snappy with twenty rows and fell apart with twenty thousand concurrent-minded users and a busy Dataverse. The formulas were not "wrong." The work was in the wrong place.
The core idea
At platform scale, canvas is the interaction surface. Dataverse (and server-side constructs) own the heavy lifting.
Delegation is not a warning to silence. It is the difference between querying the table and querying a sample. Microsoft documents that when a query cannot be delegated, Power Apps processes a limited local batch (500 by default, up to 2,000 if you raise the limit). Raising the limit does not fix the design. It postpones incomplete results until the table grows.
Concurrent users amplify chatty patterns. N+1 lookups, OnStart collection loads, and idle screens that keep querying turn a fine demo into a platform incident.
A model that stays explainable
1. Split mega-screens
One screen that owns the whole business process is hard to load, hard to unpack with PAC, and hard to review in ALM. Separate screens unpack cleanly, load less unused control tree, and give you navigation boundaries you can reason about. Prefer focused screens over a single scrolling masterpiece.
2. Design for delegation first
Write filters and sorts the data source can run. Against Dataverse, prefer simple comparisons, StartsWith, and indexed columns. Treat blue underlines as architecture debt, not editor noise. If a requirement cannot be expressed as a delegable query, move the logic: Dataverse views, calculated or rollup columns, plugins, or a narrowed first filter then local polish. Do not load "all rows" into a collection on start and pretend that is a database.
3. Stop N+1 data access
Per-cell lookups and nested galleries that each hit Dataverse create fan-out under concurrent use. Prefetch what the screen needs, use views that already shape the rowset, and filter server-side. Measure with Monitor: argue from traces, not from feelings about a spinner.
4. Put rules where the data lives
Complex eligibility, aggregation, and cross-table consistency belong closer to Dataverse than in nested ForAll on the client. Power Fx is excellent for interaction. It is a poor shared rules engine when five apps must agree. Server-side logic gives you one definition and less client payload.
5. Budget concurrent behavior, not only cold start
OnStart fan-out that looks fine for one maker becomes painful when many users open the app in the same window. Idle screens that keep timers and queries alive waste capacity. Concurrent users need fewer round trips per action and less work before first interaction. Performance budgets should include "fifty people opened the home screen at 09:00," not only "my laptop after a rebuild."
6. Keep identity and ALM in the same conversation
Even canvas apps sit in a wider identity and ALM story. Who can run the app, which Dataverse privileges they hold, and how the package moves across environments are not afterthoughts. A fast screen with the wrong security role is still wrong.

Figure 2. Even canvas apps sit in a wider identity and ALM story. Source: Microsoft Learn: app roles.
Failure modes I design against
One screen owns the process. The YAML surface becomes unreviewable. PAC diffs are noise. Load cost grows with every control you forgot was there.
Non-delegable formulas in production. Results look complete until row 501. Raising the data row limit to 2,000 schedules the same bug for later.
Collections as a warehouse. OnStart loads thousands of rows "for speed." Concurrent opens hammer Dataverse and still miss rows the filter never saw.
Business rules only in Power Fx. The next app reimplements the same eligibility. Numbers disagree. Nobody knows which formula is canonical.
Idle querying. Screens leave connections and timers running. Concurrent users pay for work nobody asked for.
Monitor never opened. Teams debate Gallery properties while the trace shows a waterfall of lookups. Without Monitor, you optimize the wrong layer.
Trade-offs
Pushing work to Dataverse means more modeling and sometimes more pro-dev help (plugins, careful views). Makers lose some "change it in the formula bar this afternoon" freedom. You gain correctness at volume and fewer surprises under concurrent load.
Splitting screens adds navigation design. Users click more. The alternative is a single screen that never finishes loading on a busy day.
Strict delegation rules slow feature delivery when a fancy client-side filter would ship tonight. Ship the fancy filter only on a proven small set, or redesign so the server can answer. Incomplete results in production are worse than a delayed story.
ALM discipline (smaller apps, clearer boundaries) costs process time. Giant single-app packages cost incident time.
What I would put on an ADR
- Screen boundaries and navigation model (no mega-screen as the default).
- What logic is Dataverse (views, calculated or rollup columns, plugins) versus Power Fx (interaction only).
- Data access patterns approved for production: delegable queries, no OnStart full-table collects, no N+1 gallery lookups.
- Performance budgets verified with Monitor, including concurrent open scenarios.
- Data row limit policy: raising above default requires a written exception and a plan to restore delegation.
- ALM packaging expectations: screen and component boundaries that unpack cleanly with PAC.
Primary references: Microsoft Learn on optimize canvas app performance and understand delegation.
Closing
If your canvas app needs an architect, start with data placement and screen boundaries, not with another container property.
Push work to Dataverse. Keep screens focused. Treat delegation and concurrency as design constraints, not after-the-fact tuning.
That is how canvas stays wonderful after the demo data grows up.
