Naive offline support is easy: cache the data, queue the writes, replay them later. The hard part is what happens when two people replay contradictory writes.
Why last-write-wins fails
The default answer to conflict resolution is a timestamp: whichever write landed last wins. It is simple, and it silently destroys data. Two reps editing different fields on the same account at the same time will overwrite one another, because the unit of conflict was set at the whole record.
In the field the problem compounds. Clocks drift, devices sleep, and queued writes arrive hours apart in an order that has nothing to do with when the user acted.
Three classes of conflict
Most business data falls into three buckets. Append-only events — a call log, a note, a visit — never truly conflict; both should survive, ordered deterministically. Counters and quantities need intent, not value, so you replay "decrement by 1" rather than "set to 42". Field edits on a shared record need per-field versioning.
Classifying data this way turns an impossible general problem into three tractable ones. It is the single most useful design decision in the whole system.
Per-field vectors and intent
Rather than versioning a record, version each field the user can edit. A rep changing a phone number and a manager changing an owner are no longer competing — they touch different versions and both apply cleanly.
For quantities, store the operation instead of the result. "Reserved 2 units" replays correctly regardless of order; "stock is now 8" does not.
Deletes and permissions offline
Deletion is the classic trap. A hard delete on the server is invisible to a client that was offline, which then resurrects the record on its next write. Use tombstones so absence is explicit rather than inferred.
Permissions are the other trap. A user who was permitted when they went offline may not be when they reconnect. The server must re-authorise every replayed operation rather than trusting the fact that it originated on a known device.
What to measure
Track replay rejection rate, median queue depth, and the count of operations requiring manual resolution. If manual resolution is more than a rounding error, your data model is fighting you — usually because record-level versioning crept back in somewhere.
The honest test is a two-day airplane-mode field trial. Not a simulation. Two days, two users, one shared record, and see what survives.
Key takeaways
- Record-level last-write-wins quietly discards one user's edits.
- Classify data as append-only, intent-based counters, or per-field edits.
- Use tombstones for deletes and re-authorise every replayed operation.
- Measure replay rejection rate; a forced airplane-mode field trial is the real test.