WhollySoftware
Back to blogMobile

App Startup Time: Profiling and Fixing Cold-Start Regressions

Wholly Software TeamJune 24, 20256 min read
App Startup Time: Profiling and Fixing Cold-Start Regressions

Cold-start regressions almost never come from one dramatic change. On a retail client's Android app, startup time had drifted from about 900ms to 2.4 seconds over six months, and no single commit was the culprit. We used Android Studio's App Startup profiler alongside Perfetto traces pulled from real devices to build a timeline of exactly what ran before the first frame, rather than guessing from code review.

The biggest single offender turned out to be an analytics SDK initializing synchronously in Application.onCreate, blocking for around 400ms while it fetched a remote config on first launch. We moved it to lazy initialization triggered after the first frame rendered, using Jetpack's App Startup library to sequence initializers explicitly instead of letting each team add its own onCreate hook.

On iOS, the equivalent problem showed up as too much work happening in application(_:didFinishLaunchingWithOptions:) — six different feature teams had each added their own setup call over a year, and nobody owned the aggregate. We used Xcode's Instruments Time Profiler with the App Launch template to get a flame graph, then moved everything non-essential to didBecomeActive or a background queue, cutting iOS cold start from 1.8s to about 950ms.

Dependency injection graphs are a quieter source of startup cost. One client's Dagger/Hilt graph was eagerly constructing a dozen singleton repositories at app launch even though most screens only needed one or two. Switching several to @Lazy injection with Hilt got us another 150-200ms back with no behavior change anywhere else in the app.

We now treat startup time as a metric with an owner and a budget, not a one-time cleanup. Every client project above a certain size gets a startup budget (typically under 1.5s cold start on a mid-tier device) checked in CI using Macrobenchmark on Android and XCTest launch metrics on iOS, so a regression shows up in a pull request instead of six months later in an app store review.

The lesson that generalizes: startup regressions are death by a thousand cuts, so the fix isn't a single heroic optimization — it's instrumenting the metric early enough that nobody can add 200ms without noticing.

PerformanceAndroidiOSProfiling
App Startup Time: Profiling and Fixing Cold-Start Regressions — Wholly Software