Skip to content

Mobile synchronization

Mobile data synchronization design

A reliable sync engine makes duplicates, delay and disconnection ordinary rather than exceptional.

Mobile System Design Blueprint (book, from $199)

Mobile synchronization: what matters most

Mobile data synchronization needs stable operation identifiers, idempotent server handling, explicit ordering and a conflict policy tied to the product domain. Store pending mutations durably before sending. Retry transient failures with bounded backoff and stop on permanent validation or authorisation errors. Record server revisions or cursors so incremental pulls can be resumed. Do not assume timestamps from different devices are trustworthy. Expose sync state so the UI can distinguish local success from remote acknowledgement. Background execution improves progress but foreground launches and user actions must also reconcile. Measure queue age, retry count, conflict rate and time since successful sync.

Separate push and pull

Local mutations and remote changes have different failure modes. Model each explicitly, then define how acknowledgement advances local state.

  • Durable operation ID
  • Idempotency key
  • Client sequence or dependency
  • Server revision cursor
  • Retry classification
  • Conflict resolution result

Name the states

One boolean called synced cannot explain what the user sees. Model the states separately.

Outcome unknown is the state people skip. A transport error after the server accepted the write looks the same as a failure. Do not mint a new operation id to retry. The server has to say how it recognises a repeat, how long it remembers, and what it returns when the same id arrives with a different payload. An id on the client protects nothing until the service honors it.

Pull has its own recovery point. If the app crashes between applying a batch and advancing the cursor, replay must be safe, and a remote change must not overwrite a pending local edit blindly.

  • Editing: the draft is in memory
  • Pending: the edit and its operation are durably recorded
  • Sending: an attempt is in progress
  • Outcome unknown: no conclusive response came back
  • Accepted: the server acknowledged the result
  • Conflicted or rejected: the change was not accepted as sent

Choose conflict rules by meaning

Last-write-wins is simple but can silently destroy intent. Field-level merge helps some documents. Server authority is appropriate for protected state. Manual resolution is necessary when neither side can safely win.

State the rule per entity rather than promising one universal algorithm.

Controlled Change builds a sync engine from its components, then gives conflicts, idempotency and reconciliation a chapter of their own.

How to choose a sync solution

Decide what the app promises offline and who owns the truth for each kind of data before you compare products. Then put the same questions to every candidate, your own build included: how it identifies and retries writes, how it resolves each conflict rule above, how it resumes from a cursor, and what it lets you observe. Run every candidate through the same cases: a response lost after acceptance, a process kill after a durable edit and before sending, an expired cursor with a remote deletion, and a sign-out with pending work followed by another account.

A solution that cannot express one of your conflict rules pushes that rule back into application code. How to choose a mobile data sync solution works through the build-or-adopt decision, and Controlled Change treats the sync engine, conflicts and version skew as one part of the architecture.

Make sync observable

Log operations without leaking private content. Track queue age and permanent failures. Give support enough correlation data to explain why one device appears stale.

In an interview, observability proves the design can be operated after launch.