Flutter · One codebase, native feel
How do you design offline support and synchronization?
Short answer
Make the local store the source of truth, queue mutations while offline, and sync with idempotent requests. Resolve conflicts explicitly and show sync state to the user.
Offline support is a data design problem before it is a UI problem. Reads need a cache with clear freshness rules. Writes need a durable outbox so they survive process death. The sync engine needs ordering, retries and conflict handling, and the UI needs honest states for pending, synced and failed.
class Outbox {
final List<PendingAction> _pending = [];
Future<void> enqueue(PendingAction action) async {
_pending.add(action);
await _flush();
}
Future<void> _flush() async {
while (_pending.isNotEmpty) {
final action = _pending.first;
try {
await api.send(action);
_pending.removeAt(0);
} on NetworkException {
return;
}
}
}
}- Persist the outbox, not only an in-memory queue; the app may be killed
- Give each mutation a client-generated id so retries are idempotent
- Define freshness per resource rather than one global cache duration
- Show pending and failed writes in the UI, with a retry action
- Handle conflicts with last-write-wins, version checks or field-level merge, and document the choice
Detecting connectivity is not enough
The device can report a connection while the backend is unreachable, rate limited or behind a captive portal. Treat connectivity as a hint and let actual request outcomes drive sync. Back off when failures repeat instead of hammering the server.
Follow-ups you should expect
Interviewers use these to check whether the first answer was understanding or memorisation.
- 1Why is an in-memory outbox insufficient?
- 2How do you make a queued write idempotent?
- 3Which conflict resolution strategy would you choose for collaborative editing?
- 4How do you test sync after process death?
Say it in the interview
I treat the local store as the working source of truth and persist an outbox for mutations. Each mutation has a client id so retries are idempotent, and sync uses backoff. Conflicts need an explicit policy, and the UI must show pending and failed states rather than claiming success. Connectivity is only a hint; actual request results decide whether sync works.
Use this as a model, not a script. Saying it in your own words is what makes it survive follow-up pressure.
Related questions
Reading is step one
Now say it out loud.
Understanding an answer and delivering it under pressure are different skills. Rehearse this topic in a live Flutter mock interview and get scored feedback on depth, clarity and confidence.