Tutorials/Power Apps/Constructing Clean Canvas Apps: A Guide to Power Apps Coding Practices
Power Appsintermediate

Constructing Clean Canvas Apps: A Guide to Power Apps Coding Practices

A practical walkthrough of naming conventions, error handling patterns, and performance strategies to keep your canvas apps scalable and maintainable.

NA
Narmer Abader
@narmer · Published June 3, 2026

Building a Power Apps canvas app that works is one step; building one that can be understood, extended, and debugged by others (or by yourself six months later) is the real challenge. Without a consistent set of coding conventions, even a moderately complex app quickly becomes a maze of disconnected variables, long formulas, and slow galleries. This article shares a practical framework for writing clean, maintainable canvas apps using a concrete scenario you can adapt to your own projects.

The Scenario: Project Task Tracker

Imagine you are creating a task management app for a small team. Your data lives in a SharePoint list called ProjectTasks with these columns:

ColumnType
TitleSingle line of text
AssignedToPerson or group
StatusChoice (Not Started, In Progress, Completed)
DueDateDate and Time

You need a gallery that displays tasks assigned to the current user and a detail screen where those tasks can be edited. All the examples that follow are based on this scenario.

1. Naming Conventions as the Blueprint

Consistent naming makes an app self-documenting. The few seconds you save by calling a control Label1 are lost many times over when you try to fix a bug.

Controls

Use a short prefix that indicates the control type:

powerfxControl naming examples
lblPageTitle    // Label
txtNewTask      // Text input
btnSubmit       // Button
galTasks        // Gallery
scrDetail       // Screen
cmpHeader       // Component
colStatus       // Collection (always hint at data shape)

Variables, Collections, and Data Sources

  • Global variables: gblCurrentUser
  • Context variables: varSelectedTaskId (use in Screen.OnVisible or Navigate context)
  • Collections: colLocalTasks
  • Data sources: use the original SharePoint/Dataverse name, e.g., ProjectTasks

Avoid single-letter variables. Prefer camelCase for variables and PascalCase for data source names.

Screens

Name screens by their function: scrTaskBrowse, scrTaskDetail, scrSettings. Avoid generic names like Screen1.

2. Screen Architecture and Navigation

For the task tracker, use at least two screens:

  • Browse screen (scrTaskBrowse) – a gallery that filters tasks for the current user.
  • Detail screen (scrTaskDetail) – a form to view and edit a selected task.

Pass the selected record via navigation context rather than a global variable:

powerfxNavigate with context
Navigate(scrTaskDetail, ScreenTransition.Fade, {selectedTask: ThisItem})

On the detail screen, capture the context into a local variable:

powerfxDetail screen OnVisible
Set(varSelectedTask, selectedTask)

This keeps the data flow clear and avoids accidental overwrites from other screens.

3. Handling Data with Delegation in Mind

Delegation is the single most common performance trap in canvas apps. The ProjectTasks list can hold thousands of records, so your gallery filter must delegate.

Good (delegable):

powerfxFilter with delegation-friendly operator
Filter(ProjectTasks, AssignedTo.Email = gblCurrentUser)

Bad (non‑delegable):

powerfxNon-delegable filter – avoid
Filter(ProjectTasks, StartsWith(Title, "Design") && Status.Value = "Not Started")

StartsWith on a text column is delegable, but && is not when combined with another filter? Actually, StartsWith is delegable; combining with a delegable condition is fine. However, Status.Value (a choice column) might not be fully delegable depending on the data source. A safer approach is to use the underlying ID or use choices directly.

For choices, filter by the value like Status = 'Not Started' (using the single-quoted status value). SharePoint choices are delegable when you use the exact value.

If a delegation warning remains, consider restructuring your data (e.g., add a calculated column) or using With to reduce the dataset locally after a delegable first step.

Use With to Cache Repeated Values

When you need to reference the same record multiple times, use With to avoid repeated lookups:

powerfxCache with With
With(
  {currentTask: LookUp(ProjectTasks, ID = varSelectedTaskId)},
  If(
      currentTask.Status.Value = "Completed",
      "Done",
      currentTask.Title
  )
)

This is especially valuable inside galleries or labels where a formula is evaluated many times.

4. Error Handling Pattern

With modern IfError and IsEmpty you can centralise error handling instead of checking Result after every Patch.

Validation before saving:

powerfxForm submission with validation
If(
  IsBlank(txtNewTask.Text),
  Notify("Title is required.", NotificationType.Error),
  IsBlank(DatePickerDueDate.SelectedDate),
  Notify("Due date must be set.", NotificationType.Error),
  Patch(ProjectTasks, Defaults(ProjectTasks), {
      Title: txtNewTask.Text,
      AssignedTo: gblCurrentUser,
      Status: 'Not Started',
      DueDate: DatePickerDueDate.SelectedDate
  });
  Notify("Task created.", NotificationType.Success);
  Reset(txtNewTask);
  Reset(DatePickerDueDate)
)

Catching errors with IfError:

powerfxIfError example
IfError(
  Patch(ProjectTasks, varSelectedTask, {Status: 'Completed'}),
  Notify("Update succeeded.", NotificationType.Success),
  Notify("Update failed: " & FirstError.Message, NotificationType.Error)
)

Use FirstError.Message to surface the description rather than a cryptic error code.

5. Performance Quick Wins

  • Trim OnStart – load only essential data. Move secondary lookups to the first screen’s OnVisible.
powerfxEfficient OnStart
Set(gblCurrentUser, User().Email);
Collect(colStatusOptions, Choices(ProjectTasks.Status));
  • Avoid unnecessary dependencies – each control that depends on another control increases formula re-evaluation. Store derived values in variables when possible.

  • Use collections for static data – if a lookup table rarely changes, load it once into a collection and use Filter on that collection locally.

  • Reduce control count – reuse components (header, footer, icons) instead of repeating them on every screen.

  • Watch the delegation bar – whenever you add a filter, check the yellow delegation warning in the upper-left corner of the formula bar. If it appears, you must rewrite the filter or the app will break with scaled datasets.

6. Common Pitfalls and How to Avoid Them

PitfallConsequenceSolution
Inconsistent namingHard to find variables and controlsAgree on prefixes and casing early; use Power Apps’ “View > Variables” and “View > Controls” panes to audit.
Ignoring delegationApp works in test but fails in productionEach time you write a Filter or LookUp, check the delegation warning.
Long formulas in single linesImpossible to readUse With to break logic into steps; use // comments inside formulas.
Hard‑coded data source namesUpdating a source name requires changing every formulaUse a global variable for the data source name and reference that. Better yet, use environment variables.
Skipping error handlingUser sees a generic dialog on failureWrap every data mutation in IfError or check IsEmpty after a Patch.

Final Recommendation

Start with a small set of standards that your team agrees on. Write them down in a shared location (a wiki or a simple markup file) and review them during pull requests or code walkthroughs. The goal is not to enforce an arbitrary style but to reduce cognitive overhead so everyone can focus on the logic that matters.

The official Power Apps canvas app coding standards provide a solid base; this article extends them with practical patterns for day‑to‑day development. Over time, evolve your own rules as the platform adds new features.

References