Problem
A consumer app used across 190+ countries felt slow to open. Retention was softening in a way no single screen explained. The launch window — the first few hundred milliseconds before the app becomes interactive — was doing too much, and users on mid-range devices and slow networks felt it most.
Solution
Treat startup as a measured budget, not a feeling. I profiled the initialisation flow end to end, attributed time to each unit of work, separated what genuinely had to run before first paint from what only felt like it did, and moved the rest off the critical path.
Technical challenges
- Startup work was spread across initialisation code that many features depended on — nothing could be removed blindly.
- Improvements had to hold on low-end Android over 3G, not just a flagship on Wi-Fi.
- The app shipped on a bi-weekly train, so changes had to be incremental and safe.
Architecture decisions
- Introduced a clear split between must-run-before-first-frame and can-run-after initialisation, with the latter deferred until after first interaction.
- Made expensive work lazy and cached results that were being recomputed every launch.
- Added a startup trace as a first-class, tracked metric so regressions surface in data.
Business impact
Faster time-to-interactive directly protects the top of the retention curve — the users most likely to abandon are new ones judging the app in its first seconds.
Results
- Measurably faster time-to-interactive for users worldwide.
- No new features and no redesign — pure engineering leverage.
- Startup became a number the team can see and defend release over release.
Lessons learned
Most teams optimise startup by guessing. The single highest-leverage move is to measure first and put a budget on the number — the fixes are usually obvious once the time is attributed, and they stay fixed only when someone owns the metric.