Offline-first is a product decision, not a library
Every team that ships to people who move discovers the same thing: the hard part was never caching. It is deciding what the software should do when it cannot ask anybody.
The request usually arrives as a technical one. Can the app work offline? The honest answer is that it can work offline in exactly the ways you decide it should, and that those decisions are not ours to make alone. They are product decisions with a technical bill attached.
A driver in a loading bay with two bars is not a network problem to be smoothed over. They are a person who has just done something — collected a signature, photographed a pallet, marked a job done — and who needs to know whether it counted.
Three questions before any code
We will not open a sync branch until these have answers, in writing, from someone who owns the process rather than the codebase.
- What may be done without the server? Reading a route, almost always. Marking a delivery complete, usually. Issuing a refund, almost never. The line is drawn by consequence, not by convenience.
- Who wins a conflict? Two people edited the same job while both were offline. Last write wins is a decision, not a default — and it is the wrong one wherever money or safety is involved.
- What does the person see while it is pending? A queued action that looks identical to a completed one is a lie the software tells on your behalf, and it is discovered at the worst possible moment.
Offline support is not a feature you add. It is a set of promises you decide you can keep, and then keep.
The queue is the product
Once those answers exist, the engineering is unglamorous and well understood. Every action
that can happen without the network becomes an entry in a durable local queue, with an
idempotency key generated on the device. The server treats a repeat of the same key
as the same action rather than a new one, which is what makes an aggressive retry safe on a
train.
The queue survives a force-quit, a flat battery and an operating system update, because it is written to disk before the user is told anything happened. If we cannot persist it, we do not acknowledge it.
Show the state, do not hide it
Interfaces that pretend everything is fine teach people not to trust them. We show three states and no more: saved on this device, sent, and needs attention. The third one is a real screen with a real action, not a red dot. It is the screen that stops a day of work quietly disappearing.
Test it by turning the radio off
Network conditioners are useful and insufficient. The tests that find the real defects are the boring physical ones: put the device in a lift, walk into a basement, switch to a foreign SIM, leave it in a queue for twenty minutes and come back. We do this on the actual hardware the client uses, and it is written into the plan as a task with hours against it, because otherwise it does not happen.
What this costs
Roughly a fifth of the build, spent on paths most users will never see. It is the least glamorous line in any estimate and the first one someone tries to cut. Our position is that if the people using the software work where the signal does not reach, this is not the optional part — the rest is.
Next noteThe second year is where design systems die