Loading…
Journey to a Faster Everyday Superapp Where Every Millisecond Counts
GrabRenu Yadav
Summary
Grab undertook an initiative to reduce startup time and improve time to interactive (TTI) on its passenger mobile app. Because local benchmarks failed to simulate real device and network conditions, the team instrumented code in production across 8–9 million daily users to capture p50 and p95 metrics. Initial gains came from caching service tiles between sessions and removing a startup animation, saving four seconds. Architectural changes followed, including converting iOS dynamic frameworks to static linking and merging others, while Android initialisation was refactored with Kotlin coroutines. Replacing a heavy third-party analytics library with an internal experimentation platform yielded further startup reductions.
Context
Rapid feature releases increased Grab passenger app startup latency, risking poor user experiences, bad reviews, and uninstalls across Southeast Asia.
Approach / What changed
Grab measured startup metrics in production, cached city service tiles, eliminated unnecessary startup animations, converted dynamic iOS frameworks to static linking using an open-source merging tool, refactored Android initialization with coroutines, and replaced a third-party analytics SDK with an in-house tool.
Takeaways
- Caching service tiles across app sessions and removing a non-functional startup animation together reduced time to interactive by 4 seconds.
- Reducing dynamically linked iOS frameworks from 107 to 12 via static linking and the CocoaPods Merge plugin dropped p90 pre-main time by 41%.
- Parallelising Android library initialisation using Kotlin coroutines and an ApplicationInitialiser class improved startup time by approximately 0.4 seconds.
Related reading
Grab ·
How Grab is Blazing Through the Superapp Bazel Migration
Grab's mobile superapp scaled past 2.5 million lines of code across both Android and iOS, leading to unsustainable local and CI build times under Gradle and Xcode. To address these bottlenecks, the engineering team analyzed their dependency trees and introduced an internal tool to calculate and optimize the build critical path. They also deployed a Kubernetes-autoscaled remote build system using Mainframer for Android and implemented Test Impact Analysis to run only affected tests in pre-merge validation. While dependency decoupling yielded modest 7% to 10% gains and iOS remote builds proved unscalable on Apple hardware, Android remote builds reduced local compile times by up to 50%, and targeted test execution reduced pre-merge pipeline durations by more than 30%.
Sergii GrechukhaGrab ·
Evolution of quality at Grab
As Grab expanded its superapp, manual QA sign-offs led to prolonged testing cycles and a peak in major production defects around 2019. To counter defect leakage and improve delivery pace, the engineering organization transitioned to a shift-left testing strategy across its software development lifecycle. Quality engineers began writing Given/When/Then acceptance tests prior to coding so that software engineers could execute them during development, accompanied by Definition of Ready and Definition of Done standards. The team also structured a multi-layer test strategy spanning unit tests, pipeline-executed UI component tests with mocked APIs, backend integration tests, and a custom internal end-to-end framework. Between 2019 and 2022, these changes reduced major and critical production issues by 60% and development-phase critical bugs by 40%.
Abby AlcantaraGrab ·
Enabling R8 optimization at scale with AI-assisted debugging
Grab experienced widespread Application Not Responding spikes across its Android superapp, driven by memory pressure and complex Jetpack Compose layouts embedded in legacy code. While switching to advanced R8 optimization promised significant performance gains, obfuscated stack traces and two-hour remote compilation cycles stalled investigation across nine million lines of code. To resolve this, engineers built Model Context Protocol tools to automate APK decompilation, deobfuscation, and code context extraction. The team paired these tools with an AI workflow that used the GitLab CLI to generate multiple solution branches and run verification builds in parallel. This strategy replaced hours of manual reverse engineering with minutes of automated analysis, allowing the team to debug and validate aggressive optimizations at scale.
Nguyen Van MinhGrab ·
App Modularisation at Scale
Grab transitioned its monolithic mobile application into a modular architecture to resolve increasing code conflicts, slow releases, and difficult team collaboration. The team decomposed the single module by establishing base infrastructure modules, shared UI and utility libraries, discrete feature modules, and bridge kit modules for inter-module communication. Dependency injection using Dagger ties these components together in the main app module while preventing feature modules from directly depending on one another. The architecture spans over 1,000 modules across the app, with more than 200 modules in the Grab Financial Group payments domain where over 95% of modules build in under 15 seconds. This approach accelerated Gradle CI and local builds through parallel compilation and caching, though it increased Gradle sync times, IDE memory usage, and configuration maintenance overhead.
Amar Jain