- 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 / conflict3. 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.
| Record | Policy | Risk |
|---|---|---|
| Preference | Field-level replacement | Overwriting another field |
| Shared text | Merge or user decision | Lost writing |
| Stock / payment | Server validation | Duplicate 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: