Study guide

3.5 Optimizing Canvas and Model-Driven App Performance

Microsoft Power Platform Developer Associate PL-400

Track your progress as you read

Finished sections get a check mark.

1 Introduction, Exam Overview & Developer Toolchain

0.1 PL-400 Exam Facts 0.2 Audience Profile & Required Developer Skills 0.3 The Power Platform Developer Toolchain 0.4 Extension-Point Map & AI in the Developer Workflow

2 Create a Technical Design

1.1 Analyzing Technical Architecture and Choosing Out-of-the-Box vs. Custom Solutions 1.2 Designing Authentication, Authorization, and Security Architecture 1.3 Deciding Where Business Logic Runs and Choosing the Right Table Type 1.4 Designing Reusable Power Apps Components and Custom Connectors 1.5 Designing Dataverse Code Components, Automations, and Integrations

3 Build Power Platform Solutions

2.1 Managing Power Platform Environments for Development 2.2 Dataverse Security Roles for Code Components, Least Privilege & Troubleshooting Operational Security 2.3 Solutions, Managing Dependencies & Solution Layers 2.4 Environment Variables & Connection References 2.5 Power Platform Pipelines & CI/CD with Power Platform Build Tools

4 Implement Power Apps Improvements

3.1 Complex Power Fx Formulas and Functions 3.2 Building Reusable Canvas Component Libraries 3.3 Invoking Power Automate Cloud Flows from a Canvas App 3.4 Troubleshooting Canvas and Model-Driven Apps with Monitor and Browser Debugging Tools 3.5 Optimizing Canvas and Model-Driven App Performance

5 Extend the User Experience

4.1 The Client API Object Model & JavaScript Form Scripting 4.2 Event Handler Registration & Navigation to Custom Pages via the Client API 4.3 Client Scripting Against the Dataverse Web API; Command Bar & Buttons with Power Fx and JavaScript 4.4 PCF Fundamentals: The Component Manifest & Lifecycle Events 4.5 Implementing PCF Component Interfaces; Device, Utility & Web API Features 4.6 Packaging, Deploying & Consuming a PCF Component

6 Extend the Platform: Dataverse Plug-ins & Custom APIs

5.1 Plug-in Fundamentals & the Event Execution Pipeline Stages 5.2 Execution Context & Implementing Business Logic in Plug-ins 5.3 Pre/Post Images & Organization Service Operations in Plug-ins 5.4 Registering Plug-ins with the Plug-in Registration Tool & Optimizing Plug-in Performance 5.5 Custom API Messages & Plug-ins That Implement a Custom API 5.6 Configuring Dataverse Business Events

7 Extend the Platform: Custom Connectors

6.1 Open API Definitions: Building and Extending a Custom Connector 6.2 Authentication and Policy Templates for Custom Connectors 6.3 Importing Definitions and Creating Connectors for Azure Services 6.4 Azure Functions in Custom Connectors and Data Transformation

8 Extend the Platform: Platform APIs & Azure Functions

7.1 Dataverse Web API Operations & OAuth Authentication 7.2 Organization Service Operations, Concurrency, Transactions & Bulk Operations 7.3 Service Protection API Limits & Retry Policies 7.4 Azure Functions for Long-Running, Scheduled & Event-Driven Workloads 7.5 Authenticating to Power Platform with Managed Identities

9 Extend the Platform: Power Automate Cloud Flows

8.1 Dataverse connector triggers/actions, trigger filters & retry policies 8.2 Complex expressions & flow control with error handling 8.3 Sensitive input/output parameters & Azure Key Vault 8.4 Reusable child flows & Microsoft Entra ID service principals

10 Develop Integrations

9.1 Publishing Dataverse Events: IServiceEndpointNotificationService & the Plug-in Registration Tool 9.2 Registering Service Endpoints: Webhooks, Azure Service Bus & Event Hub 9.3 Data Synchronization with Change Tracking & Alternate Keys 9.4 Upsert-Based Synchronization with the UpsertRequest Message

11 Exam Readiness & Practice

10.1 Cross-Domain "Where Do I Implement This?" Decision Framework 10.2 Exam-Day Strategy, PL-400 Item Styles & Study Plan

3.5 Optimizing Canvas and Model-Driven App Performance

Key Takeaways Explain This Topic AI

The App Checker's Performance tab flags large images, excessive controls, non-delegable queries, and heavy OnStart formulas.

Effective pre-loading means minimal App.OnStart plus screen-scoped OnVisible loads, not one large synchronous pull of an entire table.

Delegable, filtered queries combined with Concurrent() reduce both server load and canvas app load time simultaneously.

Model-driven form performance depends on minimizing visible fields and tabs and disabling default sub-grid data loading.

Model-driven view performance depends on limiting displayed columns and filtering or sorting on indexed columns.

Last updated: July 2026

Measuring Before Optimizing

Power Apps Studio includes a built-in App Checker , with a Performance tab that flags specific, actionable issues — large images, excessive controls on a screen, non-delegable queries, and heavy OnStart or OnVisible formulas — rather than leaving developers to guess. The blueprint's "optimize canvas app performance" sub-topic (3e) centers on two named techniques — pre-loading data and query delegation — plus a broader set of practices that reduce the amount of work the app does on load and per interaction.

Pre-Loading Data the Right Way

"Pre-loading" doesn't mean pulling every table into a giant App.OnStart collection — that pattern is a common anti-pattern that increases startup time because the app blocks on a large synchronous data pull before the first screen even renders. The recommended pattern instead:

Keep App.OnStart minimal — only global settings, user context, or small lookup tables genuinely needed everywhere.

Load screen-specific data in that screen's OnVisible , not centrally, so the cost is paid only when a user actually visits the screen.

Where data really should be cached client-side (for speed or offline use), use ClearCollect against a delegable, filtered query rather than the full table, and wrap independent loads in Concurrent() so they run in parallel instead of one after another.

Use Concurrent() broadly for any set of OnStart or OnVisible calls that don't depend on each other's results — it's one of the highest-value fixes the App Checker's Performance tab typically surfaces.

Delegation as a Performance Lever

Delegation is also fundamentally a performance concern: a delegable Filter or Sort pushes work to the server and returns only the rows needed, while a non-delegable formula silently caps results at the delegation limit and does the filtering client-side after retrieving up to that many rows — slower and less correct at scale. Raising the delegation limit setting is not a fix; it increases the number of rows pulled locally rather than solving the underlying non-delegable expression, trading a larger payload for the same fundamental bottleneck.

Reducing Control Count and Screen Complexity

Beyond data, rendering cost scales with the number of controls and rules a screen must evaluate :

  • Technique Effect
  • Minimize total visible controls per screen Fewer property formulas to re-evaluate on every state change
  • Avoid nested galleries where a flat structure works Reduces per-row control multiplication
  • Hide, don't duplicate, near-identical screens Fewer app-wide OnVisible and data triggers
  • Compress or resize images before import; prefer SVG for icons Smaller app payload, faster load
  • Limit the number of distinct data sources referenced by one screen Fewer connection handshakes on screen load

Formulas referencing Self or Parent excessively, or deeply nested If / Switch chains recalculated on every keystroke, add up the same way — the Performance tab flags screens whose combined control and formula cost crosses platform-recommended thresholds.

Model-Driven Form Performance

Model-driven apps optimize differently because forms are metadata-driven rather than formula-driven. Key levers for "optimize model-driven app performance (forms and views)" (3f):

Minimize fields and tabs on the main form — every visible field, especially those bound to formatted or calculated columns or lookups, adds retrieval and rendering cost; move rarely-used fields to a secondary tab that loads only when clicked.

Turn off default data loading for sub-grids and related-record tabs , so they lazy-load only when a user actually expands them, instead of running a query for every related entity on every form open.

Limit business rules and synchronous JavaScript on form load — each adds sequential client-side execution time before the form is interactive; asynchronous patterns and event-scoped handlers that only fire on the field or save events they actually need outperform broad on-load scripts that touch every field.

Use quick view forms sparingly — each one issues its own retrieve against the related record.

Model-Driven View Performance

Views are essentially FetchXML queries rendered as grids, so view performance follows normal query-optimization logic:

Limit displayed columns to what users need; every column adds to the query and render cost, especially formatted lookup or option-set columns.

Filter and sort on indexed columns. Dataverse automatically indexes primary keys and some system columns; sorting or filtering large tables on non-indexed custom columns is slow at scale, and heavily-filtered custom columns are good candidates for requesting a custom index.

Avoid unnecessary related-entity columns in a view, since each pulls from a joined table.

Cap default record counts sensibly and rely on server-side paging rather than large page sizes that pull excess rows the user won't scroll to.

Across both app types, the underlying principle is the same one the blueprint tests repeatedly: retrieve only what's needed, only when it's needed, and let the server, not the client, do filtering and sorting whenever delegation or indexing makes that possible.