26 July 2026

Building Apps for Unreliable Internet: A Practical Guide to Designing for Low Connectivity

Every developer eventually hits the moment where a demo that worked perfectly on office wifi falls apart the second it's tested on a real 3G connection that keeps dropping. That gap — between "works when the network is good" and "works when the network is what it actually is for most users" — is where most software for emerging markets quietly fails.

This is a practical look at how we think through that gap when we're building for unreliable internet, not just the philosophy (we've covered that in why offline-first matters) but the actual decisions that go into it.

Start by assuming failure, not connectivity

The default mental model most teams start with is: "the app calls the server, gets a response, done — and if that fails, we'll show an error." Building for low connectivity flips that assumption. The starting question becomes: what does this feature do when there is no response, for an unknown amount of time, possibly ever?

That single reframing changes almost every subsequent decision — how data is stored, what a "save" button actually does, and how errors are surfaced to a user who has no way of knowing whether the problem is their connection, their phone, or the app itself.

The core building blocks

Local-first storage. Data the user creates needs to exist and be usable on the device the instant it's created, independent of any server round trip. This usually means an on-device database (something like SQLite, or a mobile-friendly embedded store) that the app treats as its actual source of truth during a session — not a cache of server data, but the real data.

A queue, not a request. Instead of "send this to the server now," every network-dependent action becomes "add this to a queue that will be sent when possible." The user-facing action (saving a sale, submitting a form) completes instantly against the local queue; the network sync happens invisibly in the background, retrying on its own schedule.

Conflict resolution as a first-class design problem, not an edge case. If two devices go offline, make changes, and reconnect at different times, something has to decide how those changes reconcile. Depending on the data, that might be "last write wins," it might be additive (two sales logged offline just both get added), or it might need a merge rule specific to the data type. The mistake to avoid is not deciding this at all and letting whichever sync happens to run last silently overwrite the other.

Honest state indicators. Users need to be able to tell, at a glance, what's confirmed-saved-to-server versus saved-locally-pending-sync. Hiding this distinction to make the app feel "seamless" tends to backfire — the first time someone loses trust that their data was actually recorded, they stop trusting the app entirely.

What this looks like in testing

The most effective habit we've built into how we test is simple: turn the network off on purpose, early, not as a final pass before release. If a feature can't be meaningfully exercised with the network off, that's a sign it hasn't actually been designed offline-first — it's been designed online-first with an offline patch bolted on.

Where this matters most

This isn't an abstract engineering exercise — it maps directly onto real users: a field agent recording deliveries outside city coverage, a market trader logging sales between customers, a healthcare worker updating records in a facility with no reliable signal. In each case, the software either respects that reality from the start, or it becomes one more tool that "doesn't work" for the people who need it most.

If you're building something for users in exactly this kind of environment, this is the kind of problem we spend our engineering time on. Get in touch if you want to talk through the architecture for your specific case.

We use Google Analytics to understand how you use our site and improve your experience. We do not sell or share your data. You can choose to accept or decline analytics cookies.