Think about how often the logic has to run. Something the whole app needs once, like an app name or a theme color, belongs to the app. Something a screen needs fresh every time a user lands on it, like a count of new requests, belongs to that screen.
So here’s my rule: use OnStart for one-time, app-wide setup, and use OnVisible for anything that must refresh each time a screen opens. In 2026 I’d also reach for StartScreen to pick the first screen and named formulas for values that never change.
In this tutorial, we’ll compare powerapps onstart vs onvisible on one real app. You’ll see a counter prove how often each one runs, why UpdateContext only works in OnVisible, how to rerun OnStart in Studio, and what replaced Navigate in OnStart.
OnStart vs OnVisible at a Glance
Here’s the short version from my tests in the Service Desk Demo app. OnStart is a property of the App object; OnVisible is a property of every screen. If you’re unsure which variable type to set in each, my guide on global vs context variables in Power Apps covers that side.
| Feature | App.OnStart | Screen.OnVisible |
|---|---|---|
| Belongs to | The App object (top of Tree view) | Each screen |
| When it runs | Once, when the app starts | Every time a user navigates to the screen |
| In my test | gblStartRuns stayed 1 | gblVisibleRuns went 1 -> 2 after leaving and coming back |
| Set (global variables) | Yes | Yes |
| UpdateContext (context variables) | No, no screen is loaded yet | Yes |
| Rerun in Studio | App … > Run OnStart | Select the screen, or navigate to it in Preview |
| Navigate to the first screen | Retired; use App.StartScreen | Works (it’s a behavior property) |
| Timing | Non-blocking by default, may finish late | Can run in parallel with OnStart |
| Best for | App-wide setup that runs once | Screen data that must be fresh |
Build the Demo App Step by Step
Every test below runs on the same app and the same list: Service Requests on my SPGuides site. It has 623 items (620 sample requests plus 3 test rows) with the columns Title, Status, Priority, Requester and DueDate. Status is a choice column with New, In Progress and Closed.

To build the same app, sign in to make.powerapps.com and select Start with design on the Home page.

Choose Create from blank to start an empty canvas app.

Name the app and pick the Tablet format, then select Create.

In Studio, select Add data, type SharePoint in the search box and pick the SharePoint connector.

Paste your site URL (mine is /sites/SPGuides) and select Connect.

Check Service Requests and select Connect again. The list now shows up in the Data pane.

Now add the test screen. Select New screen > Blank, then select the screen, select the pencil next to its name in the Properties pane and rename it scrOnVisible. Add a second blank screen named scrParam for the round trip.
On scrOnVisible, insert four labels and set each one’s Text property to one of these names, so the screen shows the live values:
gblStartRuns
gblVisibleRuns
locNewCount
gblAppName
Add a button with the text “Go to scrParam” and this OnSelect. My post on navigating between screens in Power Apps explains Navigate in more detail:
Navigate(scrParam)
On scrParam, add a “Back” button with this OnSelect, so you can return to the screen you came from:
Back()
Three Studio moves you’ll repeat: select a control, pick the property in the dropdown to the left of the fx formula bar, then type the formula. Select Play (top right) or press F5 to preview, and press Ctrl+S to save. More beginner guides live in the Power Apps tutorials hub.
How Often Does OnStart Run Compared to OnVisible?
This is the difference that matters most, so I made each property count its own runs. In Tree view, I selected App, picked OnStart in the property dropdown and entered this formula:
Set(gblStartRuns, gblStartRuns + 1);
Set(gblAppName, "Service Desk Demo")

Then, on the same app, I selected scrOnVisible, picked OnVisible and entered the screen’s formula. It adds 1 to its own counter and counts the New requests into a context variable:
Set(gblVisibleRuns, gblVisibleRuns + 1);
UpdateContext({locNewCount: CountIf('Service Requests', Status.Value = "New")})

Selecting the screen in Studio ran OnVisible once, so gblVisibleRuns showed 1. Next I opened Preview, clicked Go to scrParam, and clicked Back. The result: gblStartRuns stayed at 1, gblVisibleRuns rose to 2, and locNewCount showed 167.

Why the gap? OnStart belongs to the app’s launch, and moving between screens isn’t a launch. OnVisible fires on every arrival, so anything you put there reruns, including the SharePoint call. Keep it light on screens users visit often.
Important: the 167 isn’t the full count. CountIf isn’t delegable to SharePoint, so Studio shows a yellow warning and the count covers only the first 500 rows. My guide on fixing Power Apps delegation warnings shows how to get an exact total.
Can You Use UpdateContext in OnStart?
No. When OnStart runs, no screen has loaded yet, and a context variable always belongs to a screen. Microsoft Learn states it plainly: you can’t set context variables with UpdateContext in OnStart.
On the same scrOnVisible screen, OnVisible has no such limit. That’s why my locNewCount lives there: UpdateContext created it when the screen opened, and only that screen can read it.
So in OnStart, use Set for global variables and Collect or ClearCollect for collections, which I cover in my Power Apps collection guide. If one screen needs several values at once, a single UpdateContext record sets them all, as in setting multiple variables at once.
Note: Status choices in my list are New, In Progress and Closed. My first try counted “Open” and got 0 with no error, because no request has that status. Check the exact choice text when you use the Power Apps CountIf function.
How to Rerun OnStart Without Reloading the App
OnVisible is easy to retest: go to another screen and come back. OnStart doesn’t rerun on navigation, so Studio gives you a menu item for it.
- In Tree view, hover over App and select the ellipsis (…).
- Select Run OnStart.
- Check your labels: on my screen, gblStartRuns showed 1 and gblAppName showed Service Desk Demo.

The same menu has Navigate to StartScreen, which tests the StartScreen formula covered below.
One catch from Microsoft Learn: when you rerun OnStart this way, variables and collections that already exist keep their values. Collect would add the rows a second time, so use ClearCollect in OnStart if you want a clean collection on every run.
Does OnVisible Wait for OnStart to Finish?
Not anymore. Non-blocking OnStart is the default, so OnStart runs at the same time as other app formulas, and the first screen’s OnVisible can run in parallel with it. A screen can even become interactive before OnStart finishes.
In my small app this never showed, because two Set calls finish almost instantly. A slow OnStart that loads a large list is a different story: a gallery or label on the first screen can read a variable before it’s set and show blank.
Microsoft’s advice is not to rely on OnStart variables inside OnVisible. If the first screen needs the data, load it in that screen’s OnVisible, or use a named formula, which has no timing gap at all.
Navigate in OnStart Is Retired: Use StartScreen Instead
Older apps often ended OnStart with Navigate to choose the first screen. That’s retired: existing apps still work, and a Retired setting brings it back for a limited time, but it slows loading because the app has to finish OnStart before showing anything.
The replacement is the App object’s StartScreen property. This is the one in the same Service Desk Demo app; it opens a screen based on a URL parameter:
If(
Param("screen") = "param", scrParam,
Param("screen") = "combo", scrComboDefault,
Param("screen") = "launch", scrLaunch
)
With no parameter, the If returns blank and the app opens on the first screen in Tree view, scrDelegation. With &screen=param in the app’s URL, it opens scrParam.
Heads up: StartScreen can’t read global variables or collections from OnStart. Use Param, User, LookUp, or a named formula there instead.
Named Formulas: The Third Option Most Apps Need
Microsoft now suggests moving cached values and global setup out of OnStart into the App object’s Formulas property. A named formula is written as name = expression, and you use the name anywhere in the app.
For the same demo app, my gblAppName and the New-request count could become these two lines in App.Formulas:
AppTitle = "Service Desk Demo";
NewRequestCount = CountIf('Service Requests', Status.Value = "New");
Learn lists four advantages: the value is always available (no wait for OnStart), always up to date when the list changes, can’t be changed elsewhere in the app, and is only calculated when a screen uses it. The trade-off is that named formulas can’t use behavior functions like Set, Collect or Navigate.
When to Use OnVisible Instead of OnStart
Here’s how I decide on a new app in 2026:
- A value that never changes (app name, colors, the current user): a named formula. Use OnStart only if you need Set.
- Data that must be fresh each time a screen opens: that screen’s OnVisible.
- A context variable for one screen: OnVisible, because UpdateContext doesn’t work in OnStart.
- Picking the first screen: App.StartScreen, never Navigate in OnStart.
- Something triggered by a click: neither one; put it in the button OnSelect property.
And don’t set the same variable in both places. With OnStart and OnVisible running in parallel, whichever finishes last wins, which makes bugs hard to reproduce.
How to Switch Logic from OnStart to OnVisible
If an old app has a long OnStart, I move it in small pieces rather than all at once:
- Save the app (Ctrl+S) so you can restore the old version.
- Find formulas in OnStart that only one screen uses, and cut them into that screen’s OnVisible.
- Change Set to UpdateContext where only that screen reads the variable.
- Move constant values into App.Formulas as named formulas.
- Replace any Navigate at the end of OnStart with an App.StartScreen formula.
- Run OnStart, then preview each screen and check the values.
So the deciding difference is frequency: OnStart ran once in my test while OnVisible ran on every visit. Add the UpdateContext rule and the retired Navigate, and most logic ends up in OnVisible, StartScreen or named formulas.
If you’re tidying up variables and data loading in your app next, these guides pick up from here:
Frequently Asked Questions
Does OnStart run again when I navigate back to the first screen?
No. OnStart runs when the app starts. In my test, gblStartRuns stayed at 1 after leaving the screen and coming back, while the screen’s OnVisible counter went from 1 to 2.
Why don’t I see the OnStart property on the App object?
Microsoft notes that OnStart might be disabled by default in some contexts, with a switch in the app’s Advanced settings to turn it on. The App object reference on Microsoft Learn lists the alternatives it recommends first.
Why is my variable blank on the first screen when OnStart sets it?
Non-blocking OnStart is the default, so the first screen can render before OnStart finishes. Load the data in that screen’s OnVisible, or use a named formula, which has no timing dependency.
Does OnVisible run when I preview a screen in Studio?
Yes. Selecting a screen in Studio ran its OnVisible once in my test, and every navigation to it in Preview ran it again. Use Run OnStart from the App menu to retest OnStart.
What is OnHidden in Power Apps?
OnHidden is the screen property that runs when the user navigates away from the screen. The Screen control reference documents it next to OnVisible.

Hey! I’m Bijay Kumar, founder of SPGuides.com and a Microsoft Business Applications MVP (Power Automate, Power Apps). I launched this site in 2020 because I truly enjoy working with SharePoint, Power Platform, and SharePoint Framework (SPFx), and wanted to share that passion through step-by-step tutorials, guides, and training videos. My mission is to help you learn these technologies so you can utilize SharePoint, enhance productivity, and potentially build business solutions along the way.