[Mobile Development]

24 Oct 2026

-

8 min read time

Mobile Startup Is a Release Metric, Not a Build Setting

Learn how to measure startup and responsiveness across real journeys, test Android build changes, and decide whether they belong in every release.

Kalle Bertell

By Kalle Bertell

A violet hand presses a stopwatch beside a phone showing its first frame and another showing a usable screen.

A faster build is not necessarily a faster app. If users still wait for a usable screen, miss a tap or hit an app-not-responding error, the optimization has failed its real test. Treat startup speed and responsiveness as release outcomes: define the journeys, measure them before changing the build, and keep a change only when release-like tests and post-release signals agree.

Grab’s gains are evidence for a process, not a target

In an October 2026 case study, Grab reported approximately 35% better cold-start time, 32.5% fewer user-perceived Android app-not-responding errors (ANRs) and 30% smaller downloads. Those are its approximate cumulative outcomes after staged work with R8, Baseline Profiles, Startup Profiles and refined keep rules. They are not the expected return from enabling a single setting in another app.

The stages matter. Grab says its 2025 first phase—R8 compatibility mode alongside Baseline and Startup Profiles—produced about 27% better cold-start time, 25% fewer user-perceived ANRs and 16% smaller downloads. It moved to R8 full mode nine months later and reported further gains. Do not add the phase percentages together or assign the cumulative result to full mode alone.

Grab also describes a useful failure mode: post-release ANR spikes and slow starts associated with reading many DEX files during initialization. Cloud Profiles did not initially cover every critical path, including Dagger dependency-graph setup. An app with different initialization work may need a different intervention. The transferable lesson is to identify the expensive path and verify that an optimization reaches it.

This is why I would not make “enable R8 full mode” the first item in a startup project. Make “show where users wait” the first item. If the build change then helps the measured journey without breaking it, it has earned a place in the release.

Define what a faster release means before measuring it

A startup scorecard needs more than one number. Record cold-start behavior, and distinguish it from warm and hot launches rather than mixing all launches into a single comparison. For the cold-start journey, measure both time to initial display (TTID) and time to full display (TTFD). TTID ends at the first frame. TTFD ends when the app reports that it is usable, for example through reportFullyDrawn(). If a screen paints quickly but leaves its essential content or controls unavailable, TTID can improve while the experience does not.

Define “usable” for the screen you are testing. On a sign-in journey, that may mean the user can enter credentials and proceed. On a returning-user journey, it may mean the main screen has the content and controls needed for the next action. The definition should match what the app reports as fully drawn; otherwise TTFD is just a second timer with an unclear endpoint.

Then choose two or three journeys where responsiveness affects the task: opening the app and navigating, signing in, or interacting with a frequently used screen. Record interaction responsiveness alongside startup. A quick launch does not tell you whether the first tap is handled promptly or whether subsequent frames hitch.

Track Google Play’s user-perceived ANR rate separately. It is the share of daily active users who experienced at least one qualifying ANR; Android vitals currently counts input-dispatching timeouts for this measure. It is not an ANR event count, and it is not a startup-duration metric. An improvement in one cannot stand in for improvement in the others.

Before a trial, name the baseline app version, representative devices, OS versions and network conditions. Keep download size on the scorecard too: it was one of Grab’s reported outcomes, but a smaller artifact is not proof of a usable launch. Decide which cohorts and journeys must improve and what reliability regression would stop a rollout. Otherwise it is too easy to pick the most flattering result after the change lands.

Trace the wait before choosing the tool

Start with a slow journey on a production-like build. On Android, use startup traces to see what runs before the first frame and before the screen becomes usable. Investigate initialization and rendering work rather than assuming the delay lives in compilation. Grab’s DEX-reading and Dagger example is a reason to inspect your own startup path, not a diagnosis to copy.

Use the same discipline across app architectures. React Native’s performance guidance distinguishes JavaScript-thread and UI-thread frame rates and recommends testing release builds. A native scroll can look smooth while JavaScript-driven touches or updates lag. Check both threads on the journey users actually take. As we argue in our React Native versus web decision guide, representative hardware and the real workflow matter more than a framework-level performance claim.

If iOS is in scope, profile its corresponding journey separately. Apple’s SwiftUI instrument in Instruments 26 brings SwiftUI updates together with Time Profiler, Hangs and Hitches, helping distinguish long view-body updates from excessive repeated updates. That is useful evidence about an iOS screen; it does not explain an Android ANR. Nor should an Android startup win be used to declare the iOS experience fixed.

The output of this step should be a bounded hypothesis: which path is slow, on which device cohort, and which proposed change could affect it. If traces point to work that profiles or R8 will not address, fix that work instead. A build-tool migration is a poor substitute for diagnosis.

Trial R8 and profiles without confusing their jobs

Baseline Profiles and Startup Profiles are related, but they act at different stages. Baseline Profiles guide on-device ahead-of-time compilation for selected code paths, including startup and interactions. Startup Profiles guide R8’s build-time DEX layout. Generate profiles from representative startup and in-app journeys; a profile built around a convenient test path can miss the initialization or interaction users actually exercise.

Begin by verifying the current R8 configuration. Trial a bounded change where practical, then compare it against the baseline. Android recommends Macrobenchmark comparisons with Baseline Profiles enabled and disabled. Its startup example uses StartupTimingMetric, StartupMode.COLD and CompilationMode.Partial(baselineProfileMode = BaselineProfileMode.Require). Add frame timing when the hypothesis concerns interaction jank. Compare equivalent compilation states; otherwise the experiment cannot tell you what changed.

Benchmark a non-debuggable variant as close to production as possible, preferably with minification enabled, on representative physical devices. Macrobenchmark can produce per-iteration traces and JSON results, so keep the underlying evidence rather than only a headline time. Inspect TTID, your defined TTFD and the relevant interaction results. If a number moves unexpectedly, a trace is more useful than another aggregate.

Before trusting a Baseline Profile result, check that baseline.prof is packaged and that the profile has actually been compiled. Its presence in a project is not evidence that it affected the measured build. Local profile benchmarks also omit Cloud Profile effects available on production devices, so their result is a controlled comparison—not a production forecast.

Treat R8 full mode as a separate correctness trial. Grab encountered reflection-dependent paths involving Gson and Java dynamic proxies, then used targeted keep rules and daily QA builds aligned with production R8 behavior. Exercise parsing, proxies, navigation, sign-in and other critical flows in an optimized release-like build. Keep mapping files and working symbolication so failures can be diagnosed. Do not accept a smaller download if a critical path fails at runtime.

Make the result a release gate

A local win earns a cautious rollout, not automatic adoption. Compare startup and ANR signals by app version and relevant device cohort after release; watch the journeys and failure modes that motivated the change. Set a rollback criterion before rollout, including what would count as an unacceptable reliability regression. Android’s profile debugging guidance notes that direct production A/B testing of different APKs for compile-time profile changes is generally not supported through Google Play. It points instead to local before-and-after benchmarks and an off-cycle small-percentage release as ways to gather evidence.

Teams improving an existing iOS, Android or React Native app can use mobile app development support for the measurement, release-build testing and monitoring work as well as the implementation. The decision still belongs to the scorecard: promote an optimization to a release default only when the targeted journey improves and reliability holds. Recheck it on later releases; initialization paths, profiles and user journeys can change.

Release checklist

  • Before changing the build: Record a baseline version; define cold-start TTID and a meaningful TTFD; choose two or three critical interactions; capture user-perceived ANR rate and download size by relevant cohort.

  • Before selecting an optimization: Trace a slow journey on representative hardware. Check both JavaScript and UI-thread behavior for React Native, and profile iOS separately when it is in scope.

  • Before accepting a benchmark: Use a non-debuggable, production-like build; compare equivalent compilation states; confirm profiles are packaged and compiled; retain traces and per-iteration results.

  • Before rollout: Run optimized release-build QA through reflection-heavy and business-critical flows. Preserve mapping files, define a rollback criterion and stage the release.

  • After rollout: Compare version- and device-level startup and ANR signals. Put reproducible benchmarks and build-configuration checks in CI, but let real-user outcomes decide whether the change remains the default.

Kalle Bertell

By Kalle Bertell

More from our Blog

Keep reading