Offline-first is a product decision, not a sync library
Decide what must keep working with no signal and how conflicts resolve before picking any offline sync technology — the library is the easy part.
- Area
- Connected Hardware
- Published
- Length
- 4 min
A team building a field, mobile or device app usually reaches for “offline support” as a technical checkbox: pick a sync library, add a local cache, done. That’s the wrong order of operations. The decision that actually determines whether the app works is which parts of the job must keep working with no signal at all, and what the app does when two versions of the same record disagree once it’s back online. Neither question has a library answer. They have to be settled against the actual job, before any technology gets chosen.
Start with what must work when there’s no signal
Say a technician is in a plant room, a lift shaft, or a warehouse basement — exactly the places mobile data doesn’t reach. If the app is a thin shell over an API, it stalls on a spinner, loses a half-filled form, and teaches the team to write the job on paper and enter it later. At that point the software has made the job slower than no software at all, which is the actual failure mode offline-first is meant to prevent.
The fix isn’t a better connection. It’s treating the phone as the primary database and the server as a replica that catches up later, for the specific tasks that have to survive a dead zone: seeing today’s job list, filling in a checklist, capturing a photo and a signature, closing a job. Every one of those has to be writable to an on-device database immediately, with the interface never waiting on a network call to show the result of a tap. Deciding this list — what must work offline versus what can reasonably wait for signal — is a conversation with whoever does the job, not a technical spec.
Conflict rules people can actually understand
Offline means two people, or the same person on two devices, can end up editing the same record without knowing it. A sync library will happily resolve that for you — last write wins, or some merge logic buried in its defaults — but a rule nobody can picture is a rule people stop trusting the first time it does something they didn’t expect.
The better approach gives every record a client-generated id so a retry can never create a duplicate, and makes a genuine conflict visible as a choice rather than a silent overwrite: “this checklist was also edited on another device — keep yours, keep theirs, or look at both.” That’s more work to build than picking a default merge strategy, but it’s the version that a technician in the field will actually trust, because it never quietly throws away something they entered.
Show the sync state, don’t hide it
An app that hides its own sync status is asking the user to take it on faith that the job closed properly. A better pattern is one visible indicator per record — synced, pending, or needs attention — so a technician closing out a day’s jobs can see, at a glance, which ones have actually reached the server and which are still sitting on the phone waiting for a signal. We built this as our own concept project, not for a named client: field service app is a concept we built to test exactly this sync and conflict-handling approach before using it on real work.
The same honesty matters for whoever manages the team remotely. A dispatcher’s view of “what’s been completed today” is only useful if it distinguishes a job that’s actually synced from one that’s sitting, unsynced, on a phone with no signal in a basement somewhere.
Media and data caps are a design decision too
Photographs and signatures are usually the heaviest things an offline app has to move, and a phone with a bad connection and a technician on a limited data plan is a realistic constraint, not an edge case. Compressing media on the device, queuing it for upload when a real connection exists, and letting the job close before the upload finishes are all product decisions, not implementation details to leave to whichever library gets picked. The alternative — a job that can’t be marked done until a large photo finishes uploading over a weak connection — recreates the exact slowdown offline-first was supposed to fix.
A checklist before you start
- Which specific tasks in this app must work with absolutely no signal, and which ones can reasonably wait for a connection?
- If two people edit the same record while both are offline, what happens — and could you explain that rule to the person using the app?
- Does every record carry an id generated on the device, so a retry can’t create a duplicate?
- Can the person using the app see, at a glance, which of their own jobs have actually synced and which haven’t?
- Have you set a real limit on how much media a job can hold, and does the app still let someone close a job before a large upload finishes?
- Are you choosing a sync technology to fit a job you’ve already defined, or defining the job around whatever the library makes easy?