Flutter · One codebase, native feel

How do you design offline support and synchronization?

Mediumofflinesyncconflict resolutioncachingUpdated Oct 2026
Quiz this track

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.

dart
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.

Do not pretend an offline write succeeded. If the backend later rejects it, the user needs a visible resolution path, especially for money or scheduling actions.

Follow-ups you should expect

Interviewers use these to check whether the first answer was understanding or memorisation.

  1. 1Why is an in-memory outbox insufficient?
  2. 2How do you make a queued write idempotent?
  3. 3Which conflict resolution strategy would you choose for collaborative editing?
  4. 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.