Tengo Meskhi, CEO of Conceptdigital6 min read

How one app went from a 35-second load to 3 seconds, and the three changes behind it

Key takeaways

  • A developer's app made about 20 network requests one after another before showing anything. On a plane's slow connection that took 35 seconds. After three changes it took 3.
  • Change 1: trust the login already on the phone, and check it with the server in the background.
  • Change 2: save a small snapshot of the home screen on the device and show it immediately on the next open.
  • Change 3: fire the remaining requests at the same time instead of one by one.
  • The cost is small and known: for a few seconds a user may see slightly old numbers, or a subscription that has just expired.
  • Most slow apps are not slow on the developer's wifi, so test on a throttled connection. That is where this problem shows up.

Most slow app start-ups are not a server problem, they are a waiting problem. In a recent reel, a developer explained how they made their app load about ten times faster without touching their servers. Before, the app waited for around twenty requests in sequence before drawing a single pixel. After, it showed a saved home screen immediately and refreshed everything in the background. Conceptdigital builds web and mobile apps and internal tools, and this is the pattern we reach for first when a client says their app "feels slow".

Key definition: A round trip is the time it takes for one request to reach the server and for the answer to come back. On home wifi it is often a few tens of milliseconds; on a train, a plane or a weak mobile signal it can be several hundred. Sequential requests wait for each other; parallel requests are sent at the same time.

Before: 20 requests in a rowOpen appHome screen, at lastAfter: saved screen firstHome screen from the phone, instantlyAll 20 refresh in the backgroundSame time axis. Illustrative, based on the reel.
Figure 1. The same twenty requests, before and after. Illustrative, based on the reel.

Why was the app taking 35 seconds to open?

Because it did everything in a queue, and showed nothing until the queue was empty. On every launch the app asked the server whether you were logged in, even if you had closed the app two seconds earlier. Then it checked your subscription, loaded today's question, your XP, your place on the leaderboard and more, about twenty requests in all, each one waiting for the one before. Sometimes a second or third loading screen followed.

The team did not notice, because they tested at home on fast internet, where twenty round trips still finish quickly. It only became obvious when the developer opened the app on a plane. That is the general lesson: load time is roughly the number of sequential requests multiplied by the round-trip time, so a design that is fine at 20 milliseconds is painful at 500.

Time to home screen vs round trip0s4s8s12s0 ms200 ms400 ms600 msRound trip per request (wifi ~20 ms, plane up to 600)20 in a row20 at onceSaved screen firstIllustrative model: requests x round trip.
Figure 2. A simple model: on fast wifi all three designs feel similar; on a slow connection only the cached design stays fast. Illustrative, not a measurement.

What were the three changes?

1. Trust the login that is already on the phone

If you were signed in last time, the app now assumes you still are and loads your account straight away. It still asks the server, but in the background. If the server says the session has ended, the app signs you out then. One blocking round trip disappears from every launch.

2. Cache the home screen aggressively

Every time you use the app, it saves a small snapshot of the home screen on the device: today's question, your streak, your XP and a few other details. On the next open it shows that snapshot immediately, before making a single request. Because the snapshot is tiny, the developer stored it in iOS UserDefaults, the simple key-value store every iPhone app already has, rather than a database. The web has the same idea under the name stale-while-revalidate: serve what you have, then fetch a fresh copy behind the scenes. It is even a standard HTTP caching directive, defined in RFC 5861.

3. Send the requests in parallel

Instead of waiting for one request to finish before starting the next, the app starts them all at once. On iOS that is a matter of starting several URLSession tasks together; in JavaScript it is Promise.all. Twenty requests in parallel cost roughly the time of the slowest one, not the sum of all twenty.

Load time on a slow connectionBefore35 secondsAfter3 secondsAbout 12 times faster on the same network.As reported in the reel, tested on a plane.
Figure 3. Load time on a slow connection, as reported in the reel.

What are the trade-offs?

They are real but small, and the developer was upfront about them.

ChangeWhat you gainWhat you give upWhen to be careful
Trust the saved loginNo wait for a login check on every openA revoked session lasts a few extra secondsBanking, health records, anything where a stale session is a security risk
Show a cached home screenThe screen appears instantly, even offlineNumbers can be slightly out of date for a momentPrices, balances, stock levels or anything a user might act on
Parallel requestsTotal wait drops to roughly the slowest requestMore simultaneous load on your serverRequests that genuinely depend on each other must still run in order

The example from the reel: if your subscription has expired, you might still see the home screen for a couple of seconds before being signed out. For a learning app that is a fair trade. For an app that moves money, the cached screen should show read-only information until the server confirms the session.

How do you test your own app on a slow connection?

Do not trust the office wifi. Make the network bad on purpose:

  • iPhone: turn on Developer Mode, then use the Network Link Conditioner in Settings to simulate a weak or lossy connection.
  • Android: the emulator can limit network speed and latency to mimic slow mobile networks.
  • Web apps: Chrome DevTools has built-in network throttling presets such as "Slow 4G".

Then open the app from cold and count two things: how many requests run before the first useful screen, and how many of those wait for each other. If the first number is above a handful, at least one of the three changes above will help.

Frequently asked questions

Will showing cached data confuse users?

Rarely, if the cached data is the kind that changes slowly, like a profile, a streak or yesterday's numbers. Refresh it within a second or two and most users never notice. Avoid caching anything a user might act on immediately, such as a balance or a price, or mark it clearly as updating.

Is UserDefaults safe for this?

For small, non-sensitive data, yes: it is designed for small amounts of app settings and state. Do not store tokens, passwords or personal data there; on iOS, secrets belong in the Keychain. For anything larger than a few kilobytes, use a proper on-device database.

Does this only apply to mobile apps?

No. Web apps suffer from the same sequential loading, and the same three fixes apply: keep the session in the browser, serve cached content first with stale-while-revalidate, and load data in parallel.

How much faster will my app get?

It depends on how many requests wait for each other today and how slow your users' connections are. The reel's app went from 35 seconds to 3 on a plane. On fast wifi the difference is smaller, but the app will still feel instant instead of merely quick.

About the author: Tengo Meskhi is CEO of Conceptdigital. He was previously at McKinsey and QuantumBlack, and Deputy CIO at Bank of Georgia.


If your app or internal tool feels slow, we can look at its start-up with you and tell you which of these changes would pay off first. Book a 30-minute call.