After years of writing SPFx web parts and C# event receivers, my first canvas app felt like cheating — I dragged a gallery onto a screen, pointed it at a list, and had a working mobile app before lunch. But "low-code" is not "no-thought." The developers who build canvas apps that scale are the ones who understand the data layer, Power Fx, and delegation. Here's the mental model I wish I'd had on day one.

Canvas vs model-driven — pick the right one

Power Apps gives you two app types, and choosing wrong is the most expensive mistake you can make:

This article is about canvas, because that's where most people start — and where Power Fx lives.

The anatomy of a canvas app

A canvas app is a tree of screens, each holding controls (galleries, forms, labels, buttons, inputs). Controls have properties, and almost every property is set with a Power Fx formula — a declarative, Excel-like expression that recalculates automatically when its inputs change.

Power Apps Studio — Contracts app
Contracts

Browse screen: a Gallery bound to a data source, with a row template of avatar, title, subtitle, and a status badge.

Connecting data

A canvas app talks to data through connectors. Add the SharePoint connector, point it at a site, pick the Contracts list, and it becomes a data source you reference by name. The gallery's Items property is just a formula that returns a table:

// Gallery1.Items — show approved contracts, newest first
SortByColumns(
    Filter(Contracts, ContractStatus.Value = "Approved"),
    "Modified",
    SortOrder.Descending
)

Inside the gallery template you reference the current row with ThisItem:

// Title label inside the gallery
ThisItem.Title

// Subtitle label
ThisItem.ContractType.Value & " · " & Text(ThisItem.ContractValue, "$#,##0")
SharePoint Choice columns come through as records, not strings — that's why you write ContractStatus.Value, not ContractStatus. Forgetting .Value is the single most common "why is my filter broken?" issue for newcomers.

Delegation — the concept that separates toy apps from real ones

Here is the most important thing in this entire article. Power Apps does not pull your whole list to the device — that wouldn't scale. Instead it tries to delegate the work (filtering, sorting) to the data source, which processes it server-side and returns only matching rows. But not every function or operator can be delegated, and the set differs per connector.

When you write a formula the source can't delegate, Power Apps silently falls back to pulling only the first 500 rows (raisable to 2,000 in app settings) and processing them locally. Your app looks fine in testing against a small list, then quietly returns wrong results in production.

Watch for the blue squiggly "delegation warning." For SharePoint, =, StartsWith, and basic Filter/Sort on indexed columns delegate; functions like Search() on some column types, or filtering across a many-lookup, often do not. Design your queries around the delegable set, and keep working sets under the row limit.

Editing data: forms and Patch

For straightforward edit screens, the Edit Form control does the heavy lifting — bind its DataSource and Item, drop in cards for each field, and call SubmitForm on a button. The form handles validation, required fields, and the write-back:

// "Save" button — OnSelect
SubmitForm(EditForm1)

// Form OnSuccess — go back and confirm
Notify("Contract saved", NotificationType.Success);
Back()

When you need precise control — write specific fields, create-or-update logic, no form control — use Patch directly:

// Approve the selected contract without a form
Patch(
    Contracts,
    Gallery1.Selected,
    { ContractStatus: { Value: "Approved" }, ApprovedOn: Now() }
)

State: variables, context, and collections

Canvas apps are reactive, so you reach for explicit state less than you'd think — but when you do, there are three tools, and mixing them up causes real confusion:

ToolScopeSet with
Global variableWhole appSet(varUser, User())
Context variableSingle screenUpdateContext({ showPanel: true })
CollectionWhole app (in-memory table)Collect(colCart, ThisItem)
// App.OnStart — load the current user once, globally
Set(gblCurrentUser, User());

// Pass a record to a detail screen
Navigate(DetailScreen, ScreenTransition.Cover, { selected: Gallery1.Selected })
Prefer the gallery's .Selected and direct references over stuffing everything into variables. The more you let Power Fx recalculate declaratively, the less stale-state debugging you'll do. Reach for Set/UpdateContext only for genuine UI state (a toggled panel, a loading flag).

Publishing

Save and Publish promotes your edits to the live version users run; Save alone only checkpoints your draft. Share the app with users or a security group, and — critically — they also need access to the underlying data source (the SharePoint list, the Dataverse table). The app is just the UI; permissions still live with the data.

The takeaway

A canvas app is a tree of controls whose properties are Power Fx formulas over connected data. Master four things — the data connector, ThisItem/Selected binding, delegation, and Patch/SubmitForm — and you can build genuinely production-grade apps fast. Skip delegation in particular, and you'll ship something that demos beautifully and fails the moment the list grows past 500 rows. Low-code rewards the developer who still thinks like one.

DS

Dhaval Shah

Cloud Solution Architect — 18+ years across SharePoint, Microsoft 365, and Azure AI.