An order form app I built once stored the entire cart in a single global variable. Every screen shared it, so every screen re-rendered on every change, and the app slowed to a crawl on mobile as the order grew. Moving cart state to context variables scoped per screen, plus a collection for the final order items, fixed it. The wrong scope, not the wrong logic, is usually what’s actually killing performance.
In this guide, we’ll explore three types of variables in Power Apps Canvas apps:
- Context Variables – For screen-specific, temporary data.
- Global Variables – For data that needs to persist throughout the app.
- Named Formulas – For dynamic, automatically computed values.
By using each type appropriately, you not only boost your app’s performance but also keep your code clean and maintainable.
Why Variable Management Matters
The way you handle variables can make or break your app. Poor variable management may lead to:
- Performance Bottlenecks: Excessive or mis-scoped variables can slow down your app, especially on mobile devices. This is particularly important when implementing offline capabilities or deep linking.
- Maintainability Challenges: When variables are scattered without clear purpose, updating or debugging becomes a nightmare.
- Memory Overload: Power Apps has memory limitations, so using the right type for the right job matters.
Over the years, I’ve seen apps that suffered from sluggish performance simply because they tried to do too much with a single global variable. The solution? Use context variables and named formulas where possible, and keep globals to a minimum.
Context Variables: Your Screen’s Best Friend
Context variables are scoped to a single screen and cleared automatically on navigation. That automatic cleanup is the entire value proposition: no cleanup code to write, and no risk of a stale value from a screen the user left three navigations ago.
Quick Reference
Scope: Limited to the screen.
Use Cases: Toggling UI elements, managing form inputs, or passing temporary data between controls.
Example: To toggle a popup’s visibility:
UpdateContext({ showPopup: !showPopup })
This simple line lets you flip the state of a popup without affecting any other screen. The beauty of context variables lies in their automatic cleanup. No need to worry about resetting them manually.
Passing Between Screens
Rather than creating global variables to pass data between screens, utilize the Navigation function’s context parameter:
// Navigate to details screen with selected ID and edit mode flag
Navigate(ScreenDetails, ScreenTransition.Cover, { itemId: Gallery1.Selected.ID, editMode: true })
On the destination screen, these become context variables (itemId and editMode) available for immediate use. This eliminates needless globals while maintaining clean data flow.
Global Variables: Use with Caution
Global variables persist throughout your app and are accessible on every screen. They’re the right tool for data like user roles or app-wide settings, and the wrong tool for almost everything else, because every global you add is memory that stays allocated for the life of the session whether it’s still relevant or not.
Important Considerations
Scope: Available app-wide.
Use Cases: Storing persistent values such as user preferences, authentication tokens, or critical configuration settings.
Example: Setting a user role:
Set(userRole, "Admin")
The question that actually matters isn’t “could this be global,” it’s “does this specific value need to survive a screen change and be visible everywhere.” Most values don’t. Default to context or a named formula, and treat global as the exception that has to justify itself.
Environment-Specific Configuration
For settings that change between environments (Dev/Test/Prod), don’t hard-code values in globals. Instead, use Environment Variables in solutions:
// In App.OnStart
Set(apiBaseUrl, EnvironmentVariableValue("API_BaseUrl"))
This approach ensures your app can move between environments without code changes, following good ALM practices.
Named Formulas: The Power of Declarative Logic
Named formulas are like self-updating equations. Once defined, they automatically recalculate whenever their dependent values change. This approach reduces the need for manual updates and keeps your data always current.
Key Points
Declarative: Automatically recalculated when inputs change.
Use Cases: Real-time calculations, data derivations, or dynamic displays.
Setup: Define named formulas at the app level (select App → Formulas in the Power Apps Studio).
Example: Creating a personalized greeting:
// Define this in App → Formulas section Greeting = "Welcome, " & User().FullName
Or, if you need to calculate a total including tax:
// Define this in App → Formulas section
TotalWithTax = TotalPrice * 1.08
Named formulas simplify your app by eliminating the need for extra variables that you’d otherwise have to update manually. They’re also perfect for values you’d previously initialize in App.OnStart, improving load performance:
// Instead of Set(DefaultTheme, "Light") in OnStart
// Define this as a named formula:
DefaultTheme = "Light"
Choosing the Right Variable Type
Here’s a quick comparison to help decide which variable type to use:
| Feature | Context Variables | Global Variables | Named Formulas |
|---|---|---|---|
| Scope | Single screen | App-wide | App-wide (computed on the fly) |
| Persistence | Temporary (cleared on screen change) | Lasts until the app is closed | No persistent storage; auto recalculated |
| Ideal Use Cases | UI state, temporary data, form inputs | User settings, authentication tokens, global flags | Dynamic calculations and derived values |
| Definition | UpdateContext({name: value}) | Set(name, value) | name = formula (in App → Formulas) |
Real-World Use Cases
Multi-Screen Order Form
In one project, I built an order form that initially suffered from performance issues because the entire order was stored in a global variable. The solution was to use context variables on each screen for selections and only a collection for the final order items. This approach works well with SharePoint list delegation for efficient data handling:
// On Product Selection Screen
UpdateContext({
selectedProduct: LookUp(Products, ID = Gallery1.Selected.ID),
quantity: 1
});
// On Order Confirmation Screen - add to a collection
Collect(orderItems, {
productID: selectedProduct.ID,
quantity: quantity,
price: selectedProduct.Price * quantity
});
// Compute order summary once
Set(orderSummary, {
totalItems: CountRows(orderItems),
totalCost: Sum(orderItems, price),
orderDate: Now()
});
This approach localizes data to where it’s needed, improving performance significantly. When working with external data sources, it’s important to follow Power Automate error handling best practices to ensure robust data operations.
Dynamic Dashboard Settings
For a management dashboard, storing user preferences like theme and default view is essential. Using a global variable for this makes sense because the settings must persist across all screens:
// In App.OnStart - initialize preferences
If(
IsBlank(userPreferences),
Set(
userPreferences,
{
theme: "Light",
defaultView: "Summary",
refreshInterval: 15
}
)
);
Later, toggling the theme becomes a breeze:
Set(
userPreferences,
Patch(
userPreferences,
userPreferences,
{ theme: If(userPreferences.theme = "Light", "Dark", "Light") }
)
)
This single global record holds multiple settings, keeping your app’s configuration organized and easily accessible. Remember that these settings will reset when the app closes unless you persist them to a data source.
Always-Up-to-Date Calculations
In an inventory app, I needed to show real-time alerts for low-stock items. Instead of juggling global variables, I used a named formula:
// Define in App → Formulas section
LowStockItems = Filter(Products, Quantity < ReorderLevel)
This formula always provides an up-to-date list without any extra code, ensuring that your users see the current state of inventory at a glance.
Common Pitfalls and How to Avoid Them
Memory Overload
The Issue: Overusing global variables can lead to memory bloat, slowing down your app. This matters even more when implementing offline capabilities, where everything you cache locally also has to be tracked in memory.
The Fix:
Use context variables where possible.
Clear globals when they’re no longer needed:
Set(userRole, Blank());For large collections, clear them when done using them:
Clear(temporaryProducts);
Confusing Scope
The Issue: Mixing up context and global variables can make your app’s behavior unpredictable. This can be particularly problematic when working with connection references across different environments.
The Fix: This is a rule that has to be enforced at the team level, not left to individual discipline; a naming convention nobody checks is just a suggestion. When I led our Power Platform Governance Team, we put two things directly into the peer review checklist instead of a style guide nobody reads: a prefix convention (gbl for globals, ctx for context), and a requirement that any new global state its justification in the PR description, specifically why it couldn’t be a context variable or named formula instead. Making the justification a required line in the review, not an optional best practice, is what actually changed behavior across the team.
Circular Dependencies in Named Formulas
The Issue: When named formulas reference each other, it can create a calculation loop.
The Fix:
Introduce intermediate variables to break the cycle:
BaseTotal = Price * Quantity; DiscountRate = If(BaseTotal > 1000, 0.15, 0.1); TotalWithDiscount = BaseTotal * (1 - DiscountRate)
This clear, one-way dependency chain makes your formulas reliable and easier to debug.
Performance Issues with App.OnStart
The Issue: Loading large datasets or initializing many variables in App.OnStart can significantly slow your app’s startup time.
The Fix:
- Use named formulas for constants and defaults instead of Set() in OnStart.
- Load data incrementally or on-demand rather than all at launch.
- For multi-screen apps that need different first screens, use App.StartScreen property instead of Navigate() in OnStart.
Accessibility Considerations
When using variables to control UI visibility or state:
When toggling elements (like with
showPopup), ensure keyboard focus is properly managed. When a popup appears, set focus to a control within it, and when it closes, return focus to the triggering element.For dynamic content changes driven by variables, use the “Live” property on labels (set to “Polite” or “Assertive”) to ensure screen readers announce important updates.
Maintain sufficient color contrast when using variables like
userPreferences.themeto toggle between visual modes.
Best Practices
Use Context for Temporary State:
Use context variables for any data that’s only needed on one screen.Minimize Globals:
Reserve global variables for truly app-wide data. If a value is only used in one area, keep it local.Favor Named Formulas for Calculations:
Use named formulas to ensure that derived data always reflects the latest values without manual updates.Use Navigation Context:
Pass data between screens using the Navigate function’s context parameter rather than creating globals.Clean Up:
Explicitly clear variables and collections that are no longer in use to free up memory.Enforce It, Don’t Just Document It:
A naming convention in a wiki page gets ignored. The same convention as a required line in your peer review checklist gets followed.Use Environment Variables:
For settings that change between environments (Dev/Test/Prod), use Environment Variables in solutions rather than hard-coding values.
Key Takeaways
- Context variables for anything scoped to a single screen; they clean up automatically on navigation.
- Global variables for genuinely app-wide state only. Every global you add is memory that stays allocated for the life of the session.
- Named formulas for anything derived. They recalculate automatically and remove a whole category of manual
Set()calls. - Use the navigation context parameter to pass data between screens instead of reaching for a global.
- Environment Variables, not hard-coded globals, for anything that changes between Dev/Test/Prod.
Audit one existing app against this list. A global that should have been a context variable or a named formula is usually where the sluggishness is coming from.
Discussion
Loading comments...
Leave a comment
Your email is required but will never be displayed publicly.