PowerApps canvas app coding standards and guidelines Part 1.

To be continued…….. Part 2

General coding guidelines.

Click targets

If actions should be performed when a group of controls is clicked, there are three approaches that you can use:

  • The simplest approach is to group the controls and then assign click events to the group’s

OnSelect property.

  • Put the code in one of the controls in the group (the most significant control), and then add Select(controlWithLogic) to the OnSelect property of all the other controls in the group. As for the first approach, no additional controls are required, and the controls can easily be selected in the editor.
  • Lay a transparent rectangle on top of the group, and use the rectangle’s OnSelect property.

We recommend the third approach, because code isn’t affected as much if the controls in the group change. This approach also gives the maker more flexibility about the shape of the clickable region. Although the controls inside the rectangle are more difficult to select directly on the screen, you can select them individually in the Screens pane on the left side of the editor.

For more information about this approach, see the article HOW TO: Use Transparent Rectangles Effectively In a PowerApp article by Todd Baginski.

Variables and collections

Context variables

Limit your use of context variables. Try to use them only when they’re absolutely necessary.

Know when to use context variables versus global variables. Use a global variable when you need it to be available on all screens. Use a context variable if you want to limit the scope of a variable to a single screen.

Avoid passing context variables between screens when a global variable might be more appropriate (and much easier to debug).

Update all necessary context variables in a single UpdateContext call. In this way, you make your code more efficient and easier to read.

For example, use this call to update several context variables.

Don’t use these separate calls.

Global Variables

Don’t use multiple variables when you can use just one. Here’s an example of multiple variables.

Instead, you can use just one variable, as shown here.

Limit your use of collections. Try to use them only when they’re absolutely necessary. Use ClearCollect instead of Clear; Collect.


To count the records in a local collection, use CountIf instead of Count(Filter()).


Avoid using unnecessary DataCards and canvases, especially if they have nested galleries. Avoid nesting in other operators too, such as the ForAll function.

Note: A previous version of this document stated that nested galleries would be deprecated. This is incorrect and we apologize for the error.

Optimizing for performance

OnStart code

The OnStart property is invaluable for those one-time calls that are needed to initialize your apps. It might be tempting to put your data initialization calls in this property too. However, while OnStart code is running, the user will continue to see the app splash screen and a “Getting your data” message, and the perceived load times will be longer.

For a better user experience, we recommend that you let the home screen be shown with placeholders for data, such as double dashes (–). Then fill in the data after it’s retrieved. In this way, the user can begin to read content on the home screen or interact with controls that aren’t data-dependent. For example, the user can open an About screen.

Concurrent function

PowerApps runs your data source calls from top to bottom in a module. If you have several calls, this linear execution can negatively affect app performance. One workaround for this issue has been to use timer controls to concurrently fire data calls. However, this approach is difficult to maintain and debug, especially when some timers depend on other timers. The Concurrent function eliminates the need to use timer controls to make multiple data calls at the same time. The following code snippet replaces several API calls that used to reside in the OnTimerStart property of timer controls in the app. This approach is much easier to maintain.

To fire these calls, you can put them in the OnVisible property. Alternatively, if that approach becomes too messy, you can put the calls in a timer control, and set the variable referenced in the

timer’s Start property either in the OnVisible property or in the OnSelect property of a hidden control. You can also combine timers with other controls to show a loading message while the code in the OnVisible property run. This approach is a great way to let your users know that the app is doing something. For more information, see the Finding the best place for your code section earlier in this white paper.

Note: To make code easier to maintain, you might prefer to use the OnVisible property. However, if you use OnVisible, you won’t be able to use the Navigate function.

To see the Concurrent function in action, see Todd Baginski’s video, HOW TO: Use the Concurrent Function To Make Your PowerApps Perform Better.

Delegable calls vs. non-delegable calls

When you call your data sources, be aware that some functions are delegable, but others aren’t. Delegable functions can be evaluated on the server and will be more performant. Non-delegable functions require that data be downloaded to the client and evaluated locally. This process is slower and more data-intensive than a delegable call.

For more information, see the Understand Delegation in a Canvas App article.

Using local collections

For smaller datasets, especially when frequent access is an issue, consider loading the datasets into local collections first. You can then perform your functions on, or bind controls to, those collections. This approach will be especially beneficial if you make frequent non-delegable calls. Just be aware that there will be an initial effect on performance because the data must be retrieved and there are limits on the number of records that are returned. For more information, see Mehdi Slaoui Andaloussi’s great blog post, Performance considerations with PowerApps.

SQL optimization

Your organization might be using Azure SQL Database for your data back end, to take advantage of its rich administration capabilities and interoperability. However, a poorly implemented design won’t handle concurrency, and you might have to increase the database transaction unit (DTU) size and, therefore, the cost.

For example, Microsoft IT built the Thrive Conference app for an internal conference that had 1,700 attendees. The back end was a 100-DTU SQL Database instance. During performance testing, Microsoft asked 120 employees in its operations center to open the app simultaneously. The app stopped responding. Network traces showed that HTTP 500 errors were thrown from the PowerApps connection object. The SQL logs indicated that the server was fully utilized, and that calls were timing out.

Because there was no time to rewrite the app before the conference, Microsoft IT increased the scale to 4,000 DTU to meet the concurrency requirements. Therefore, the cost was significantly higher than the 100-DTU server that was originally budgeted. Since then, Microsoft IT has optimized the design by using the approach that’s described here. Now, a 100-DTU server is more than enough to handle the load, and the SQL calls are substantially faster.

Delegable functions for SQL

After you’ve read the previous section for an overview of delegation, see the list of data sources and supported delegation to understand which top-level functions and which predicates of the Filter and Lookup functions are supported. This information will make a big difference in the performance of your PowerApps apps, especially on mobile devices, because the whole dataset doesn’t have to be downloaded and evaluated on the client.

Using views instead of tables

Instead of traversing from table to table to get your data, expose views where the joins have been made for you. Provided that you’ve correctly indexed your tables, this approach should be very fast, and it will be even faster if you limit the results by using a delegable function that runs on the server.

Using stored procedures through a flow for performance

The biggest performance improvement that you can make for a PowerApps app that uses Microsoft SQL Server is to call stored procedures from an implementation of Microsoft Flow (that is, a flow). This approach has the added benefit of decoupling your database design from the PowerApps app.

Therefore, you can change the underlying table structure without affecting your app. As we’ll explain

later, this approach is also more secure.

To use this approach in a PowerApps app that already uses the SQL Server connector, you must first completely remove the SQL Server connector from the app. Then create a new SQL Server connector that uses a SQL sign-in that’s restricted to EXECUTE permissions on stored procedures in the database. Finally, in the flow, call the stored procedure, and pass in the parameters from the PowerApps app.

For a detailed explanation of how to create the flow and return its results to PowerApps, see Brian

Dang’s article, Return an array from a SQL Stored Procedure to PowerApps (Split Method). This approach has these performance benefits:

  • The stored procedure will be optimized through a query execution plan. Therefore, data will be returned faster.
  • Delegable calls become less of an issue, because your stored procedure will be optimized to read or write only pertinent data.
  • Your optimized flow is now a reusable component. Therefore, it’s available to other makers in the environment for common read and write scenarios.

Expensive calls

Some of your data or API calls will be expensive or time-consuming. Long execution times will affect your perceived performance. Here are some tips:

  • Don’t make expensive calls before the next page is opened. Try to make the loading of the next page instantaneous. Then, on the next page, in the background, make the calls in the OnVisible property.
  • Use a loading message box or spinner to let the user know that progress is being made behind the scenes.
  • The Concurrent function is a great way to make your calls to run in parallel. However, when this approach is used, long-running calls can block subsequent code from running.

Here’s a bad example in an OnSelect property that goes to the next page.

Here’s a better example. First, here’s the code in the OnSelect property.

And here’s the code in the OnVisible property in the next page.

Limiting the package size

Although PowerApps does a lot to optimize app loading, you can take steps to reduce the footprint of your apps. A reduced footprint will be especially important for users of older devices, or users in locales where there’s higher latency or reduced bandwidth.

  • Evaluate the media that are embedded in your app. If something isn’t used, delete it.
  • Embedded images might be too big. Instead of PNG files, see whether you can use SVG images. However, be careful about using text in SVG images, because the font that’s used will have to be installed on the client. A great workaround when you need to show text is to superimpose a text label over an image.
  • Evaluate whether the resolution is appropriate for the form factor. The resolution for a mobile app doesn’t need to be as high as the resolution for a desktop app. Experiment to get the right balance of image quality and size.
  • If you have unused screens, delete them. Be careful not to delete any hidden screens that only app makers or administrators use.
  • Evaluate whether you’re trying to fit too many workflows into one app. For example, do you have both admin screens and client screens in the same app? If so, consider breaking them into individual apps. This approach will also make it easier for multiple people to work on the apps at the same time, and it will limit the “blast radius” (amount of testing) when app changes require a full test pass.

Periodically republishing your apps

The PowerApps product team is continually optimizing the Power platform. Sometimes, for backwards compatibility, these optimizations will apply only to apps that are published by using a certain version or later. Therefore, we recommend that you periodically republish your apps to take advantage of these optimizations.

Advanced settings

The PowerApps product group offers preview features that makers can optionally turn on for their applications. Some of these features can give your apps a significant performance boost. For example, the Delayed load feature turns on lazy loading for your application. Then, during the initial load, the runtime will load only the screens and code that are required to show the first screen.

Use these features at your own risk, and be sure to test your apps thoroughly when you experiment with these features.

App design

Using parent/child relationships for relative styling

We recommend that you use one control’s style as the basis for styling other controls. In general, use relative styling for the color, fill, x, y, width, and height properties.


Use galleries for almost everything that’s repetitive and linear.

The “brute force” (manual placement of multiple controls) method might be faster initially, but it will be very time-consuming to modify later.

If you must present a series of information or controls that seem repetitive, always consider whether you might be able to create a internal collection by using a gallery.

It’s also useful to use a Gallery control as a view form, instead of using a Display Form control.

For example, you have a three-screen “app from data” app. There’s a Users data source that contains the user’s name, job title, and phone number.

The first screen, the User List screen, has a control that’s named galUsers. This control lists all users.

The second screen, the User Details screen, just has a gallery control that’s named galUserDetails. The Items property of this control is set as shown here.


{Title: “User Name”, Value: galUsers.Selected.DisplayName},

{Title: “Job Title”, Value: galUsers.Selected.JobTitle},

{Title: “Phone Number”, Value: galUsers.Selected.PhoneNumber}


This method is much faster than trying to modify three separate data cards in a display form.


Use forms for repetitive data entry fields.

Forms also let you quickly group several fields instead of having to use several text boxes.

A form is much easier to work with than individual text boxes, because forms let you to take advantage of parent/child relationships to implement relative styling.

Common Data Service for Apps

We recommend that you use a single screen to handle edit/insert operations.

If possible, use a CardGallery control to handle updates to data, instead of referencing individual controls in a Patch function.

When you name context variables, you should indicate which record they’re associated with.

Multiple form factors

When you make the same PowerApps app target both phone and tablet layouts, first create one version of the app, run it through testing, and finalize it. Then convert it to the other version before you modify the layout and screens. This approach helps guarantee that your expressions, controls, variables, data sources, and so on, all have the same names. Therefore, it’s much easier to support the apps and develop them. To learn how to convert one form factor to another, see the How to convert a PowerApp from one layout to another article on Todd Baginski’s blog.

Configuration values

You likely use SaveData and LoadData to store user-defined settings in your mobile apps. They provide a handy way of caching data.

Note: SaveData and LoadData work only inside the PowerApps player client app. Keep this limitation in mind as you design your apps, because these functions won’t work when PowerApps apps are loaded in web browsers.

Your app will probably need to have application settings that can be easily changed in one place, such as color schemes, URLs to other apps, or settings that define whether debugging controls are visible on app screens. Therefore, the people who deploy your application can quickly set those values, and there’s less risk that the code will be messed up during deployments. Think of these settings like an ASP.NET web.config file.

Here are several approaches to storing configuration values, in order of increasing difficulty.

Creating a hidden configuration screen

A surprisingly easy way of setting configuration values is just to create a hidden screen and put your configuration values in text input controls. In this way, you can change application settings without editing code. To use this approach, follow these steps:

  1. Make sure that the configuration screen isn’t the first screen in the application. Put it anywhere else in your screen order. We recommend that you make it the last screen, so that it’s easily found.
  2. Make sure that your users can’t go to the screen.
  3. Give yourself a way of going to the screen. The easiest way is to make the screen accessible only when the app is edited, and then manually go to the screen. On the home screen of the app, you might even have a hidden button that’s only visible to app makers and admins, and that lets them go to the configuration screen. You can verify that users are app makers or admins by checking their email address (for example, check User().Email) or their AAD group membership, or use the PowerApps for Makers connector.

The following example is from the Microsoft PowerApps Company Pulse sample template. Here, you can see text input controls that let the PowerApps admin configure application setting values.

Here, you can see the name of the control that stores the Twitter account settings value.

Here, you can see where the value is used to return tweets for the Twitter account from the Twitter connector.

Although this approach is the easiest way of changing values, it does have some downsides:

  • You must republish the app to change values and make them persist.
  • Because values persist in the app, you must create a process that updates these values before you export the app in preparation for a move to another environment.

Storing configuration values in Common Data Service for Apps

Alternatively, you can create a new Common Data Service for Apps entity and store configuration values there. Because the values persist outside the app, they can be modified at any time without redeploying the app. Common Data Service for Apps entities can have unique values per environment. For example, URLs can be different in pre-production and production environments.

Although this approach is a great way of maintaining configuration values, it also has downsides:

  • Unlike the text input control approach, this approach requires a call-back to Common Data Service for Apps. Therefore, there will be a slight effect on performance, and if Common Data Service for Apps is unavailable (for example, if the user is on a mobile device and loses his or her connection), the app might not be shown correctly.
  • Because there’s no caching, a new call will be made every time the app is opened.
  • There’s no monitoring if the call fails. You’ll have to rely on your users to inform you of app failures.

Using a custom API

Although implementation approach is the most difficult, Microsoft IT has had success with an Azure app service that stores configuration values as name/value pairs in Azure Table storage.

An OAuth secured custom connector fetches the configuration values, and output caching (which includes cache invalidation as values change) enhances performance. Azure Application Insights with alerts sends notifications when there’s an issue and makes it much easier to troubleshoot a user session.

Error handling/debugging

Toggle controls for error handling

In the OnTimerStart property section, we demonstrated one pattern that you can use to handle errors with Timer controls. Another pattern that you can use to handle errors involves a Toggle control.

The following illustration shows this approach.

In this approach, logic for validation and/or error handling can be encapsulated inside a single control. The Toggle control can evaluate complex conditions and issue a true or false value. Other controls can then reference that value to show/hide error messages, change font or border colors, make buttons unavailable, log to Application Insights, and much more. If you make this control visible and editable, the app maker can switch the error condition on and off to watch the user interface (UI) react. This approach can save time and effort when you develop or debug the app.

Using a canvas control as a debug panel

As you’re developing your app and testing it, you can use a canvas control to create a semi-transparent debugging panel that appears over the top of your screens. This panel can then have editable fields, toggles, or other controls, as needed, so that you can change your variables while the app is in play mode.

For a step-by-step instructional video, see PowerApps – Best Practices: Debug Panel by Brian Dang.

Showing debug controls to app makers

You don’t want to show your debug controls to all your users. Therefore, you must either manually toggle the Visible property of your debug control (in PowerApps Studio) or automatically toggle control visibility for certain users.

One elegant approach is to add the PowerApps for Makers connector. Despite the name, this connector can be used by non-makers for read-only calls. Then call the GetAppRoleAssignments function to determine whether the signed-in user is a maker for the current app.

For this example, you’ll then set the Visible property of your debug controls to gloIsMaker, so that those controls appear only to app users who have maker permissions.

The benefit of this approach is that you won’t need to use a configuration table to specify special debug permissions.

You can also show and hide debug controls for just app makers or admins by checking their email address (for example, check User().Email) or their AAD group membership.


Code comments

As of June 2018, you can add comments to your code. As you write code in your application, be sure to heavily comment it. Comments will help you when you return to your application months later, and the next developer who works on the app will thank you for them.

There are two kinds of comments:

  • Line comments: If a double forward slash (//) is added to any line of code, PowerApps will treat the rest of the line (including the //) as a comment. Use line comments to explain what happens next. You can also use them to temporarily disable a line of code without deleting it (therefore, they’re useful for testing).
  • Block comments: Any text that’s wrapped inside /* and */ will be treated as a comment. Whereas line comments comment out only a single line, block comments can comment out multiple lines. Therefore, they’re useful for multiline comments (such as a code module header). You can also use them to temporarily disable multiple lines of code while you’re testing or debugging.

We recommend that you add comments after you use the Format text feature, especially if your comments precede a code block. The Format text feature uses the following logic for existing comments:

  1. If a property begins with a block comment, the next line of code will be appended to it.
  2. If a property begins with a line comment, the next line of code won’t be appended to it. Otherwise, the code will be commented out.
  3. Line and block comments everywhere else in the property will be appended to the previous line of code.

Don’t worry about adding too many comments or comments that are too long. All comments will be stripped out when PowerApps creates the client app package. Therefore, they won’t affect the package size or slow down the app download or loading times.

Documentation screens

We recommend that you create screens to document the collections and variables that are used in the PowerApps app. Don’t link to these screens from the other screens in your app. These screens are seen only when the app is open in edit mode.

Here’s an example from the Microsoft PowerApps Company Pulse sample template.

This document is provided “as-is.” Information and views expressed in this document, including URL and other Internet Web site references, may change without notice. You bear the risk of using it.

Some examples are for illustration only and are fictitious. No real association is intended or inferred.

This document does not provide you with any legal rights to any intellectual property in any Microsoft product. You may copy and use this document for your internal, reference purposes.

Thanks for your tolerance.

If it’ll help you, so share it with others.