If I get one technical question when evaluating a mobile team, I ask how they handle offline state and conflict resolution.
Not because every app needs offline support. Most do not, at least not fully. I ask because the answer is almost impossible to fake, and because it maps directly onto whether a team has operated apps in the real world or only built them in an office with good wifi.
Why this question works
Offline is where mobile stops being a thin client and becomes a distributed system.
The moment a device can accept a write it cannot immediately send, you have two copies of the truth and a merge problem. Everything unpleasant about distributed systems arrives at once — ordering, idempotency, partial failure, clock skew, and a user interface that has to represent uncertainty without confusing anyone.
You cannot reason your way through this from first principles in an interview. Either a team has been through it or they have not.
What the answers sound like
"Our app requires connectivity."
Sometimes legitimate. Frequently it means the question has not been considered, and the app will behave badly on the Underground, in a lift, in a hospital basement, or on a train through the Cotswolds.
Follow up: what happens if the network drops mid-submit? If the answer is a spinner that never resolves, or a duplicate record when the user retries, you have your answer.
"We use last-write-wins."
An actual strategy, and defensible for genuinely single-user data — settings, drafts, personal preferences. Silent data loss for anything collaborative.
Follow up: what if two devices belonging to the same user edit the same record? A team that has shipped will immediately know whether that case exists in their app and what happens.
"We queue mutations and replay them."
Now we are somewhere. The follow-ups that matter:
- Are the mutations idempotent, and how is that enforced? Client-generated IDs is the usual answer.
- What happens when a replayed mutation fails validation because the server state moved? Is it dropped, retried forever, or surfaced to the user?
- Is ordering preserved across dependent operations — create-then-update on the same entity?
- How large can the queue get, and what happens when it exceeds that?
A team that has run this in production answers these quickly and mentions at least one thing they got wrong first time.
"We use CRDTs."
Sometimes exactly right, particularly for collaborative text or list structures. Sometimes an impressive-sounding answer to a problem that a mutation queue would have solved in a fifth of the time.
Follow up: which CRDT, for which data, and what is the memory profile on a low-end Android device after a year of history? The last part is where the real answers live.
The parts everyone underestimates
Three specifics that separate a working implementation from one that mostly works.
Clock skew. Device clocks are wrong, sometimes by a lot, and users change them. Any conflict strategy that relies on device timestamps for ordering is broken in a way that will not show up until it does. Server-assigned sequence numbers or logical clocks are the workable answers.
Schema migration with a queue in flight. You ship an update. Some users have pending mutations queued in the old shape. Those mutations still have to apply. This is genuinely hard and it is the source of some of the nastiest data bugs I have seen — teams that have hit it once never forget it.
Representing uncertainty in the UI. The state is not "saved" or "unsaved" — it is "accepted locally, not yet confirmed, possibly about to be rejected." Most apps flatten this into a checkmark and then confuse the user later when something silently changes. Teams with production experience have opinions about this, usually strong ones.
The AI wrinkle
Newer and increasingly common: if the app has AI features, the offline story gets a second dimension.
Inference typically requires connectivity, which means an AI feature is an online feature unless you have shipped an on-device model. That has consequences for how you present availability — a feature that silently degrades is worse than one that clearly states it needs a connection.
There is also a queuing question. If a user triggers an AI action offline, do you queue the request? If the underlying data has changed by the time it executes, is the result still meaningful? Usually not, which argues for failing fast rather than queuing — but it is a decision, and it should be a conscious one.
Why this generalises
The reason I lean on this question so heavily is that it is a proxy. A team with a considered answer on offline sync almost always has considered answers on the other things that matter — background processing, push reliability, migration strategy, crash triage, what happens when the store rejects a submission.
Production experience is a single trait that shows up everywhere. Offline sync is just the cheapest place to test for it.
The wider guide to evaluating UK app companies — 2026 cost ranges, agency archetypes, compliance requirements and contract terms — is here, and our mobile app development work covers the architecture side in more depth.
Frequently Asked Questions
Does every mobile app need offline support?
No, and building full offline capability into an app that does not need it is a common and expensive mistake. But every app needs a considered answer for what happens when the network drops mid-operation — even if that answer is a clear error state and a safe retry rather than a sync engine.
Is last-write-wins ever acceptable?
For genuinely single-user, single-device data such as settings, drafts and preferences, yes. For anything collaborative, or anything a user might touch from two devices, it produces silent data loss. The test is whether the same record can be edited from two places; if it can, last-write-wins will eventually destroy something.
Why is clock skew such a problem for sync?
Because device clocks are frequently wrong and users can change them. Any conflict resolution strategy that orders operations by device timestamp will produce incorrect merges in ways that are extremely hard to reproduce. Server-assigned sequence numbers or logical clocks avoid the whole class of bug.
What happens to queued mutations when I ship a schema change?
They still have to apply, in their old shape, after the update. This is one of the hardest problems in offline sync and a common source of serious data corruption. Handling it usually means versioning queued mutations and maintaining migration paths for in-flight items — teams that have hit this once design for it thereafter.
How should AI features behave offline?
Usually by failing fast and saying so, rather than queuing. Inference generally needs connectivity, and a queued AI request may produce a meaningless result if the underlying data changed before it executed. A feature that clearly states it needs a connection is better than one that silently degrades.
Top comments (0)