Business Professionals
Power BI | Power Pivot | Power Query | DAX
Cloud Flows | RPA | AI Builder | Copilot
60+ Formulas | Data Stories | Advanced Reporting & Modeling
VB Programming | Report Automation |
MS-Office Automation
Techno-Business Professionals
Power BI | Power Query | Advanced DAX | SQL - Query &
Programming
Microsoft Fabric | Power BI | Power Query | Advanced DAX |
SQL - Query & Programming
Power BI | Power Apps | Power Automate | Copilot Studio | Power Pages | Dataverse
Microsoft Power Apps | Microsoft Power Automate
Power BI | Adv. DAX | SQL (Query & Programming) |
VBA | Python | Web Scrapping | API Integration
Power BI | Power Apps | Power Automate |
SQL (Query & Programming)
Power BI | Adv. DAX | Power Apps | Power Automate |
SQL (Query & Programming) | VBA | Python | Web Scrapping | API Integration
Power Apps | Power Automate | SQL | VBA | Python |
Web Scraping | RPA | API Integration
Technology Professionals
Power BI | DAX | SQL | ETL with SSIS | SSAS | VBA | Python
Power BI | SQL | Azure Data Lake | Synapse Analytics |
Data Factory | Databricks | Power Apps | Power Automate |
Azure Analysis Services
Microsoft Fabric | Power BI | SQL | Lakehouse |
Data Factory (Pipelines) | Dataflows Gen2 | KQL | Delta Tables | Power Apps | Power Automate
Power BI | Power Apps | Power Automate | SQL | VBA | Python | API Integration
Power BI | Advanced DAX | Databricks | SQL | Lakehouse Architecture
Business Professionals
Power BI | Power Pivot | Power Query | DAX
Cloud Flows | RPA | AI Builder | Copilot
60+ Formulas | Data Stories | Advanced Reporting & Modeling
VB Programming | Report Automation |
MS-Office Automation
Techno-Business Professionals
Power BI | Power Query | Advanced DAX | SQL - Query &
Programming
Microsoft Fabric | Power BI | Power Query | Advanced DAX |
SQL - Query & Programming
Power BI | Power Apps | Power Automate | Copilot Studio | Power Pages | Dataverse
Microsoft Power Apps | Microsoft Power Automate
Power BI | Adv. DAX | SQL (Query & Programming) |
VBA | Web Scrapping | API Integration
Power BI | Power Apps | Power Automate |
SQL (Query & Programming)
Power BI | Adv. DAX | Power Apps | Power Automate |
SQL (Query & Programming) | VBA | Web Scrapping | API Integration
Power Apps | Power Automate | SQL | VBA |
Web Scraping | RPA | API Integration
Technology Professionals
Power BI | DAX | SQL | ETL with SSIS | SSAS | VBA
Power BI | SQL | Azure Data Lake | Synapse Analytics |
Data Factory | Azure Analysis Services
Microsoft Fabric | Power BI | SQL | Lakehouse |
Data Factory (Pipelines) | Dataflows Gen2 | KQL | Delta Tables
Power BI | Power Apps | Power Automate | SQL | VBA | API Integration
Power BI | Advanced DAX | Databricks | SQL | Lakehouse Architecture
LEARN THIS HANDS ON
Power Apps & Power Automate
Power Apps performance tuning is mostly about a handful of repeatable patterns: how you load data, how you filter it, and how you talk to Dataverse. This article walks through concrete patterns you can apply today to speed up galleries, forms, and server calls in real apps, not just demos. If you’re building larger solutions across the Power Platform, these patterns sit nicely alongside more structured platform skills like a solid Power Apps & Power Automate workflow.
Before touching formulas, it helps to know where the bottlenecks usually are.
Typical causes:
Filter() / LookUp() calls per controlOnVisible or OnStart that could be cachedOnSelect logicPatch() calls for related recordsPerformance tuning is mainly:
Galleries are often the slowest part of an app. The good news: they respond well to a few simple patterns.
Instead of calling Dataverse in every gallery, load once and reuse.
Pattern: Use OnStart or OnVisible to populate collections.
Example (App OnStart):
// Load core data once
ClearCollect(colProjects, Projects);
ClearCollect(colTasks, Tasks);
// Optionally, preload reference data
ClearCollect(colStatuses, Statuses);
Then bind galleries to the collections:
Items: colProjects
Benefits:
When not to use this:
For large tables, always push the heavy filtering to Dataverse.
Good pattern:
Items: Filter(Projects, Status = 'Status (Projects)'.Active)
Then refine locally:
Items:
Filter(
Filter(Projects, Status = 'Status (Projects)'.Active),
StartsWith(Title, txtSearch.Text)
)
The outer Filter is delegable (simple equality); the inner StartsWith may be delegable depending on connector, but if not, you’re at least filtering a smaller set.
Common slow pattern:
Items:
Filter(
Projects,
IsBlank(Manager) || DateDiff(StartDate, Today()) < 30
)
This can easily break delegation.
Better pattern: Split into delegable and non-delegable parts:
// Delegable part
With({
baseProjects: Filter(Projects, DateDiff(StartDate, Today()) < 30)
},
Filter(baseProjects, IsBlank(Manager))
)
Or pre-process into a collection:
// OnStart or OnVisible
ClearCollect(
colRecentProjects,
Filter(Projects, DateDiff(StartDate, Today()) < 30)
);
// Gallery Items
Filter(colRecentProjects, IsBlank(Manager))
Every control inside a gallery multiplies rendering work.
Practical rules:
Text properties into variables or collections.Example: heavy label calculation
Text:
If(
ThisItem.Status = 'Status (Projects)'.Delayed,
"Delayed by " & DateDiff(ThisItem.DueDate, Today()) & " days",
"On track"
)
Better pattern: precompute once when data loads.
// OnStart or OnVisible
ClearCollect(
colProjects,
AddColumns(
Projects,
"StatusText",
If(
Status = 'Status (Projects)'.Delayed,
"Delayed by " & DateDiff(DueDate, Today()) & " days",
"On track"
)
)
);
// Label in gallery
Text: ThisItem.StatusText
Forms are convenient, but the defaults are not always fast.
Slow pattern:
Update properties of card controls.Better pattern:
Example: set a variable before editing a form.
// OnSelect of gallery row
Set(varSelectedProject, ThisItem);
EditForm(frmProject);
Bind the form to the variable:
Item: varSelectedProject
This reduces repeated LookUp() calls and keeps the form lean.
Single huge forms slow down rendering.
Patterns:
// Tab selection
Set(varActiveTab, "General");
// Visible properties
frmGeneral.Visible: varActiveTab = "General"
frmFinancial.Visible: varActiveTab = "Financial"
Real-time validation feels nice but can hammer performance.
Slow pattern:
If() or LookUp() in OnChange of text inputs.Better pattern:
OnSuccess or OnSelect of the save button.Example: simple flag on change
// OnChange of txtBudget
UpdateContext({
ctxBudgetInvalid: Value(txtBudget.Text) < 0
});
Full validation on save:
// OnSelect of btnSave
If(
ctxBudgetInvalid,
Notify("Budget must be positive", NotificationType.Error),
SubmitForm(frmProject)
);
Dataverse is powerful, but chatty usage kills performance. Focus on the shape and frequency of calls.
Patch() operations with collectionsSlow pattern:
// Inside a ForAll over a large set
ForAll(colTasksToUpdate,
Patch(Tasks, ThisRecord, { Status: 'Status (Tasks)'.Completed })
);
This fires a call per record.
Better pattern: use Patch() with a collection (where possible) or reduce the set first.
// Filter down first
ClearCollect(
colTasksToComplete,
Filter(colTasks, ShouldComplete = true)
);
// Then patch in one go (connector-dependent)
Patch(Tasks, colTasksToComplete, { Status: 'Status (Tasks)'.Completed });
If the connector doesn’t support collection patching, at least ensure colTasksToComplete is small and pre-filtered.
LookUp() to DataverseRepeated LookUp() calls are a common hidden cost.
Slow pattern:
// Label in gallery
Text:
LookUp(Users, UserId = ThisItem.OwnerId).FullName
This runs once per row.
Better pattern: join once using AddColumns.
// OnStart or OnVisible
ClearCollect(colUsers, Users);
ClearCollect(
colProjectsWithOwner,
AddColumns(
Projects,
"OwnerName",
LookUp(colUsers, UserId = OwnerId).FullName
)
);
// Gallery
Items: colProjectsWithOwner
// Label
Text: ThisItem.OwnerName
Now the LookUp runs once per project instead of per render.
Concurrent() for independent callsWhen you need multiple datasets, load them in parallel.
// OnStart
Concurrent(
ClearCollect(colProjects, Projects),
ClearCollect(colTasks, Tasks),
ClearCollect(colUsers, Users)
);
This cuts overall load time when the calls don’t depend on each other.
Reference tables (statuses, categories, small lookups) are perfect for caching.
Pattern:
// OnStart
ClearCollect(colStatuses, Statuses);
ClearCollect(colCategories, Categories);
// Controls
Items: colStatuses
Items: colCategories
You avoid hitting Dataverse for every dropdown, and the app feels much snappier.
Performance is also about when you ask for data.
OnStart for global data, OnVisible for screen-specificGuideline:
OnStart:
OnVisible:
Example:
// App OnStart
Set(varCurrentUser, User());
ClearCollect(colStatuses, Statuses);
ClearCollect(colProjects, Projects);
// Screen OnVisible
ClearCollect(
colTasksForProject,
Filter(Tasks, ProjectId = varSelectedProject.ProjectId)
);
OnVisible when navigating frequentlyIf users bounce between screens, heavy OnVisible code will be felt.
Pattern:
OnStart, initial load).OnVisible, only refresh what genuinely changes.Example: instead of reloading all projects each time:
// Bad: Screen OnVisible
ClearCollect(colProjects, Projects);
// Better: App OnStart
ClearCollect(colProjects, Projects);
// Screen OnVisible: only refresh if needed
If(varProjectsDirty,
ClearCollect(colProjects, Projects);
Set(varProjectsDirty, false)
);
Set varProjectsDirty to true after any operation that changes projects.
You don’t get a built-in profiler, but you can still measure.
Practical tactics:
Example:
// Before data load
Set(varLoadStart, Now());
ClearCollect(colProjects, Projects);
Set(varLoadDuration, DateDiff(varLoadStart, Now(), TimeUnit.Seconds));
// Show on debug label
Text: "Load: " & varLoadDuration & "s"
Temporary debug labels
CountRows(colProjects).Gradual rollout
Pick one screen with a slow gallery, and refactor it to this standard pattern:
OnStart or OnVisible).AddColumns.Once you see the difference, apply the same pattern to the rest of your app – it’s the fastest way to get real performance gains without rewriting everything.
Power Apps
New
Next Batches Now Live
Power BI
SQL
Power Apps
Power Automate
Microsoft Fabrics
Azure Data Engineering