Slow App Startup: Root Causes and Fixes (2026 Guide)

App startup is the first impression and a strong abandonment driver. Google's research shows a 2-second cold start is the practical ceiling before abandonment climbs sharply. This guide covers how to

March 07, 2026 · 3 min read · Common Issues

App startup is the first impression and a strong abandonment driver. Google's research shows a 2-second cold start is the practical ceiling before abandonment climbs sharply. This guide covers how to measure startup, the common causes of slowness, and fixes that actually move the number.

Types of startup

Cold is the hard one and the one you should benchmark.

How to measure

Android


adb shell am start -W com.example/.MainActivity
# TotalTime: 842

TotalTime is the time from launch intent to first drawn frame. Benchmark on a real mid-tier device (not emulator, not flagship). Aim:

iOS

Pre-main latency + main thread until first frame. Xcode: Product → Profile → Time Profiler / App Launch template.

Jetpack Macrobenchmark (Android)


@Test
fun startup() = benchmarkRule.measureRepeated(
    packageName = "com.example",
    metrics = listOf(StartupTimingMetric()),
    iterations = 5,
    startupMode = StartupMode.COLD,
) {
    pressHome()
    startActivityAndWait()
}

Gives you median, 90th percentile, with stable numbers in CI.

Common causes

1. Heavy Application.onCreate

The most common. SDKs initialized synchronously: Firebase, Crashlytics, Segment, Amplitude, Mixpanel, Adjust, Branch. Each takes 50-200ms. Ten SDKs → 1-2 seconds.

Fix: App Startup library (Android Jetpack). Declare initializers with dependencies, lazy-init anything not needed for first frame.


class CrashlyticsInitializer : Initializer<FirebaseCrashlytics> {
    override fun create(context: Context): FirebaseCrashlytics = FirebaseCrashlytics.getInstance()
    override fun dependencies(): List<Class<out Initializer<*>>> = listOf(FirebaseInitializer::class.java)
}

2. Splash activity doing work

SplashActivity loads config, checks auth, pre-warms caches. All synchronously on UI thread.

Fix: Splash is display only. The work happens in the real first activity, or better, in Dispatchers.IO while the real activity renders.

3. Main activity layout too expensive

Deep view hierarchy, 50+ views, ConstraintLayout with 20 constraints. Inflation + measure + layout + draw takes 200ms on low-end.

Fix:

4. Early database query

Room initialization synchronous; first query runs on main thread.

Fix: Initialize Room from Dispatchers.IO. Use LiveData / Flow so queries are async by default.

5. Early network call

App launches, fetches user profile before showing UI.

Fix: Show UI first, fetch async, update when ready. Stale cache better than blank screen.

6. Image / asset decoding

Large PNG in a launcher icon, decoded on main thread.

Fix: WebP for assets. Decode on background thread via image loading library.

7. Dex / ART compilation on first install

Android's first launch of a new version compiles classes. One-time cost but user-visible.

Fix: Baseline Profiles (Android 9+). Ship profile files that pre-compile hot paths. 20-30% startup improvement typical.

8. Multi-process overhead

App has content providers or services in separate processes. Each needs separate init.

Fix: Audit android:process tags. Merge unless truly separate.

iOS-specific

Pre-main time

Dynamic linker loads all Mach-O images, runtime initializers, +load methods.

Fix:

Storyboard heavy

Initial storyboard loads 10 view controllers even though first screen uses one.

Fix: Programmatic init for first screen or split into multiple storyboards.

Benchmark targets by device class

Device classCold start targetWarm startHot start
2023 flagship< 400ms< 150ms< 50ms
2023 mid-tier< 600ms< 200ms< 80ms
2022 budget< 1000ms< 350ms< 150ms
2019 budget< 1800ms< 600ms< 250ms

Pass all four or the app feels slow to the long tail.

Baseline profiles (Android)

Ship pre-compiled profile files in your APK. They tell ART which classes and methods to pre-compile at install time. Cold start drops 20-30%.

Generate once via Macrobenchmark:


@OptIn(ExperimentalBaselineProfilesApi::class)
@Test fun generate() = baselineProfileRule.collectBaselineProfile("com.example") {
    pressHome(); startActivityAndWait()
    // Your critical user journey
}

Commit the output to src/main/baseline-prof.txt. Rebuild. Startup faster.

How SUSA measures startup

SUSA records cold start time as part of every exploration. The impatient persona abandons the session if startup exceeds 3 seconds — surfacing when startup regresses. Performance monitor samples CPU, memory, and FPS continuously, so you can see if startup is CPU-bound (decoding, parsing) or I/O-bound (disk reads, network).

Report includes:


susatest-agent test myapp.apk --persona impatient --steps 30

Fixes in order of ROI

  1. Baseline profiles — 20-30% cold start, zero user-code change
  2. Defer SDK init — 200-1000ms typically
  3. Move work off main — 100-500ms
  4. Flatten UI hierarchy — 50-200ms
  5. Fewer dynamic frameworks (iOS) — 100-500ms

Startup is a solvable problem. A 3-second cold start can usually reach 1 second in one engineering sprint. Prioritize — it is one of the highest-leverage perf investments you can make.

Test Your App Autonomously

Upload your APK or URL. SUSA explores like 10 real users — finds bugs, accessibility violations, and security issues. No scripts.

Try SUSA Free