How We Reduced App Load Time by 60%

How We Reduced App Load Time by 60%
📌

Executive Summary & Key Takeaways

A client came to us with a mobile app that was losing users. Analytics showed that 35% of sessions ended before the first screen fully loaded. The app was functional but painfully slow. This is what we found, what we changed, and how we measured it.

Table of Contents
  1. Starting With a Proper Performance Audit
  2. What We Found
  3. Image Optimization Techniques
  4. Parallelizing API Calls and Adding Request Caching
  5. Moving Analytics to Non-Blocking Background Queues
  6. Code Splitting and Lazy Screen Loading
  7. The Result

A client came to us with a mobile app that was losing users. Analytics showed that 35% of sessions ended before the first screen fully loaded. The app was functional but painfully slow. This is what we found, what we changed, and how we measured it.

Speed is a feature. Every second of load time quietly costs you users, and most teams never measure what they are losing.

Why performance pays

Starting With a Proper Performance Audit

Before changing anything, we profiled the app using React Native's built-in Performance Monitor and Flipper. Profiling without measurement first is guesswork. You end up optimizing things that don't matter while the actual bottleneck stays untouched.

The profiling session identified four distinct problem areas. The JavaScript thread was consistently hitting 60ms+ frame times during the initial load. Network requests were sequential rather than parallel, meaning each API call waited for the previous one to complete. Images were loading synchronously and blocking the render. And three third-party SDKs were executing initialization code on the main thread during app startup.

Before optimising anything, we measured. Images and JavaScript were carrying almost all of the weight.
Before optimising anything, we measured. Images and JavaScript were carrying almost all of the weight.

What We Found

  • Images were uncompressed PNGs averaging 800KB each, loading synchronously at startup
  • Seven API calls fired sequentially - the last one couldn't start until the first six finished
  • No local caching meant every screen re-fetched all data on every visit
  • Three analytics and advertising SDKs initialized synchronously on the main thread
  • The navigation library was loading all screen components at startup instead of lazily

Image Optimization Techniques

Image optimization alone reduced the initial load payload by 40%. We converted all images from PNG to WebP format, which achieves equivalent visual quality at 25 to 35% smaller file sizes. All product images were compressed to under 80KB. Background and decorative images were compressed further to under 30KB.

We implemented lazy loading using the FastImage library, which replaced the default React Native Image component. FastImage uses a more aggressive caching strategy and loads images progressively. Above-the-fold images load at full priority. Images below the initial viewport load only when they're about to enter view. This reduced the amount of data fetched on first load by 60%.

Parallelizing API Calls and Adding Request Caching

The app needed data from seven different endpoints to render the home screen. Previously, those requests ran in sequence. The home screen couldn't render until all seven calls completed, meaning users waited for the slowest endpoint, which averaged 800ms. Total wait time was over 3 seconds just from API calls.

We refactored the data fetching layer to use Promise.all() for independent requests and implemented a request caching layer using React Query. Independent calls now run in parallel, and the home screen renders progressively as data arrives rather than waiting for all of it. Cached responses serve immediately on subsequent visits while fresh data loads in the background.

  • Parallel API calls reduced API wait time from 3.2 seconds to 900ms
  • React Query's stale-while-revalidate pattern made repeat visits feel instant
  • Cache invalidation was set per-endpoint based on how frequently that data changes
  • User-specific data cached for 5 minutes, product catalog cached for 30 minutes
  • Critical path data (user auth state, core navigation data) cached persistently across sessions

Moving Analytics to Non-Blocking Background Queues

The three SDKs running on the main thread during startup were adding approximately 600ms to the initial load time. The analytics SDK, the crash reporting SDK, and the in-app messaging SDK all needed to initialize before the app could fully render. None of them needed to be ready before the user could interact with the app.

We deferred SDK initialization using the InteractionManager API, which schedules work after the initial render and any ongoing interactions are complete. Analytics events that fired before initialization completed were queued locally and flushed once the SDK was ready. This removed 600ms from the critical path with zero functional change to the app's behavior.

What 60% faster actually delivered
62%
Faster load - 4.2s down to 1.6s
28%
Longer sessions once the wait was gone
12%
Early drop-off, down from 35%

Code Splitting and Lazy Screen Loading

React Navigation was configured to load all screen components at app startup. This meant even screens the user might never visit in a given session were parsed and loaded into memory on launch. We implemented lazy loading for all screens outside the main tab navigation using React.lazy() and dynamic imports.

The settings screen, onboarding flow, and secondary detail screens were all moved to lazy-loaded bundles. This reduced the initial JavaScript bundle parse time by 35% because the engine didn't need to process code for screens the user hadn't navigated to yet.

The Result

Load time dropped from 4.2 seconds to 1.6 seconds - a 62% improvement. Session duration increased by 28% because users who previously bounced during the slow load were now staying. The 35% early drop-off rate fell to under 12% within 30 days of the release.

The app didn't get new features. It didn't change visually. It just stopped wasting users' time. Performance isn't a feature you add later. It's a quality standard that should be built in from the start, and measured continuously against real device benchmarks, not desktop emulators.

TECHNICAL CONSULTATION

Building something similar?

Talk to our senior engineering team about your architecture, roadmap, and delivery timeline. 100% on-time delivery guarantee.

Request a Technical Review →

Related Reading

← Back to all posts