Engineering10 June 2026 · 8 min read
Performance Budgets for Mobile Apps That Stay Fast
Apps do not become slow in one release. They erode, one unmeasured regression at a time. Budgets — with numbers, owners, and CI enforcement — are how fast apps stay fast.
Yeti Technology
No release meeting ever approved "make the app slower". Yet most apps get slower every quarter, because slowness arrives in increments too small to veto: one more SDK in startup, one more observer on the hot path, images a size up from what the screen needs. Each is invisible in review. The sum is an app users describe as heavy.
The countermeasure is boring and effective: budgets. Numbers, agreed in advance, measured on real hardware, enforced automatically. Here are the budgets we set on app engagements and how we keep them honest.
The budgets that matter
- Cold start to interactive: under 2 seconds on a mid-tier device — not the newest phone in the office. Warm start well under 1.
- Frame time: sustained scroll and transitions within the display's frame budget — 8.3ms on 120Hz hardware — with hitch rate tracked, not eyeballed.
- Memory: a steady-state ceiling per screen class, and zero growth across a repeated open-close cycle of every major flow (the cheapest leak detector there is).
- Payloads: a size budget per screen-load and per image, enforced at the API contract, because the fastest bytes are the ones never sent.
- Battery and data: background work quantified per day; anything scheduled must justify its wake-ups.
- App size: a download-size ceiling, watched per release — size creep is performance creep users pay for up front.
Measure on the phones your users actually own
Store dashboards will tell you the truth: a large share of your Android sessions are on hardware several tiers below your development device, and plenty of iOS sessions are on phones four or five years old. Budgets verified only on flagships are fiction. Keep a small bench of representative devices — one mid-tier Android is worth more than three emulators — and make it the reference for every number above.
Startup is a supply chain problem
Cold start is where budgets die quietly, because startup cost accumulates by default: every SDK wants to initialise first, every module wants its cache warm. Treat the launch path as a supply chain with a manifest — everything on it is there by decision, initialised lazily unless it provably must run before first frame. Audit it every release; SDKs added mid-quarter have a way of appearing in the launch path uninvited.
Enforcement lives in CI, not in vigilance
Human attention does not scale to every merge. The budgets that survive are wired into delivery: startup and frame benchmarks in CI on real or representative devices, size diffs posted on every pull request, and a release gate that treats a budget breach like a failing test — either fix it, or consciously re-set the budget in writing.
- Benchmark cold start and key-flow frame times in CI (macrobenchmarks on Android, XCTest metrics on iOS).
- Fail or flag the build on regression beyond an agreed tolerance.
- Post download-size and dependency diffs on every PR so growth is a reviewed decision.
- Track field metrics — Android vitals, MetricKit — against the same budgets, because the lab is not the fleet.
- Review budgets quarterly: they should tighten as the product matures, not silently loosen.
When the budget is already blown
Inherited a slow app? Resist the instinct to optimise everything. Profile first, on the reference device, and let the data pick the fights: it is almost always a short list — startup initialisation, an over-drawn list, oversized images, a chatty sync loop — that accounts for most of the felt slowness. Fix the top of the list, set the budgets so it cannot regress, and only then descend to the long tail. Fast apps are not the ones with the most optimisation; they are the ones where slowness has nowhere to hide.