Who is this for?
Flutter, React Native, iOS and Android teams building for unreliable networks.
Before you start
A local database, authenticated sessions and versioned server records.

1. Define which actions work offline

Drafting a note can succeed locally while payments or limited stock need server approval. Distinguish locally accepted from server-confirmed states in the UI. Persist pending actions across application restarts. An in-memory array is not a durable offline queue, and silently presenting pending data as final misleads users.

2. Persist an outbox

Save the local change and outbound action in one local transaction. Assign a stable operation identifier and retain it during retries. The server uses it to recognize completed business effects. A timeout does not prove the operation failed: the response may have been lost after commit.

operation_id | entity_id | base_version | payload | state
abc-123      | note-42   | 7            | {...}   | pending
pending → sending → acknowledged / conflict

3. Choose conflict rules per record

Device clocks are unreliable conflict arbiters. A version check can detect an update based on stale state. Collaborative text might need merging or a user decision; profile preferences might use field-level replacement. Payment and stock require server rules. Do not apply last-write-wins indiscriminately.

3. Choose conflict rules per record
RecordPolicyRisk
PreferenceField-level replacementOverwriting another field
Shared textMerge or user decisionLost writing
Stock / paymentServer validationDuplicate consumption

4. Handle deletion and account changes

Use deletion markers or a change log so an old offline device does not resurrect a deleted record. Associate queued actions with their original account. Pending work for account A must never be submitted using account B’s session. Coordinate sensitive local data cleanup with the product’s pending-work recovery policy.

5. Test interrupted delivery

Disconnect after sending, close before receiving the response, reconnect devices in different orders and delete a record on one device. Verify no duplicate effect, lost change or cross-user access. Use bounded backoff with jitter rather than synchronized retry storms.

  • A repeated operation identifier has one business effect.
  • Conflicts remain visible until resolved.
  • Track queue length and oldest pending age.
  • Offer recovery choices instead of silent data loss.

Action summary

  • Persist changes and the outbox together.
  • Keep identifiers stable across retries.
  • Define conflict and deletion policies explicitly.

Common questions

Is a read cache enough?

No. Durable writes, safe retries and conflict resolution need additional design.

Does Firebase offline behavior transfer to a custom API?

No. Implement and test the client synchronization contract separately.

Sources and scope

Technical references are listed below. Examples illustrate implementation in your own environment; they are not customer benchmarks or claims of live Uygulama Cloud services. Check the current provider documentation before applying settings.

Sources checked:

Read next

Browse all articles