Field note27 October 2026 · 3 min read

Offline-first in practice: queues, retries and honest sync states

Practical patterns for field apps that must work with no signal: local queues, idempotency keys, conflict rules and sync states that users can trust.

Offline-first doesn't mean an app that works offline now and then. It means an app that does its job on the phone first and syncs when a connection shows up. Build it that way and signal stops being something you apologise for.

These are the habits that make it dependable, and the traps that make it feel flaky.

Begin with the worst moment

Picture the signal dying halfway through a save, in the middle of a payment, or with five records still unsent. Design so that moment is boring. Most of the rest follows from that.

Write to the phone first, and keep a queue

Save every change on the device before you touch the network. Instead of syncing raw state, keep a queue of actions: record a sale, confirm a delivery, add a note. Each one is a small record that never changes once it's written. It carries an id made on the phone (a UUID), who did it, when, the details, and a status: waiting, sending, confirmed, or needs attention.

Give every action an idempotency key

Retries are only safe if the server can recognise a repeat. Send the action's id with each request, and let the server ignore ids it has already handled, returning the original answer. Then a dropped response can't create a second sale or a double payout.

Retry like a good neighbour

Wait a little longer after each failure, and add some randomness, so a thousand phones that reconnect at once don't hammer your server together. Keep payloads small. Batch where it helps. Make big uploads, like photos, resumable. And don't poll in a tight loop on someone's data bundle.

Pick conflict rules for each kind of data

One rule won't fit everything. For money and stock, the server decides: apply actions in order, and if one can't be applied, reject it with a reason the person can read and act on. For notes and form fields, merge field by field, or choose last-writer-wins on purpose and show when a value changed. Whatever you pick, never drop someone's work silently. If something has to be thrown away, say so.

Tell the truth about where the data is

People trust an app that's honest with them. Use plain labels like "Saved on this phone", "Sending…", "Confirmed" and "Needs attention", and say why and what to do next. Show how many actions are still queued. Never show a success message for something that only exists on the device, especially when money is involved. Where it makes sense, let people share or export a record, say through a message, so an urgent item isn't stuck behind a bad connection.

Plan for shared phones

In plenty of workplaces, one phone serves several people. Keep each person's queue separate, decide what sign-out does (and don't wipe unsynced work without a warning), and use a short PIN or a similar check instead of leaving a session open for whoever picks the phone up next.

Mind the data budget

Send less. Compact payloads, only what changed, no background polling, static files cached after the first visit. Test on a mid-range Android over a slow, throttled connection, not on your laptop's fibre. Respect the browser's data-saver signal when it's there.

Know where browsers let you down

Support for background sync and similar features varies by browser and operating system, and storage can be limited or cleared when space runs low. So don't make correctness depend on a background task. Sync when the app is open, when it comes back online, and when the user asks. Request persistent storage where it's available, and test on the phones your users actually own.

Try to break it

Switch on airplane mode in the middle of a save. Kill the app while it's sending. Change the phone's clock. Fill the storage. Reconnect with a hundred queued actions. If it recovers without losing or duplicating anything, you're in good shape.

Offline-first matters most where connections and devices are toughest, like agriculture, health and trade. It also goes hand in hand with careful payment handling, which we cover in designing for the M-Pesa callback that never arrives.