Builds local-first mobile storage with an optimistic local store, durable mutation outbox, per-entity conflict-resolution rules, incremental pull, and idempotent background retry. Use when someone says "the app has to work offline", "how do I sync Room or SQLite or Realm with the server", "what happens when two devices edit the same record", or offline edits must reconcile with the server later. Do NOT use for paginating, caching, and refreshing read-heavy server lists - use pagination-and-sync-engineer instead; and do NOT build offline write support for strong-consistency operations like payments or inventory counts - disable those offline.
Click to play with sound.
---
name: Mobile Offline Sync
description: Builds local-first mobile storage with an optimistic local store, durable mutation outbox, per-entity conflict-resolution rules, incremental pull, and idempotent background retry. Use when someone says "the app has to work offline", "how do I sync Room or SQLite or Realm with the server", "what happens when two devices edit the same record", or offline edits must reconcile with the server later. Do NOT use for paginating, caching, and refreshing read-heavy server lists - use pagination-and-sync-engineer instead; and do NOT build offline write support for strong-consistency operations like payments or inventory counts - disable those offline.
---
# Mobile Offline Sync
Make the local store the source of truth the UI reads and writes, and treat the network as eventual replication. The hard part is never the happy path - it is reconciling divergent edits made while offline. The costly failure is an ad-hoc "retry the request later" queue that double-applies mutations, resurrects deleted rows, and silently destroys one user's edits with another's.
## Operating procedure
### Step 1: Gather inputs
Collect per feature before designing:
1. The entities that must work offline, and for each: single-owner or multi-writer? Whole-object edits or field-level edits?
2. The maximum realistic offline window (a field-service app may need 7-30 days; a consumer app usually hours). This sets tombstone retention.
3. The local store (Room, SwiftData, SQLite, Realm) and whether the server API can accept client-generated UUIDs and return per-record versions.
4. Which operations are strong-consistency (payments, inventory decrements, seat booking) - these get disabled offline, not synced.
5. Expected data volume per user, which decides pull batch sizes.
Label unknowns as guesses and validate them against the server team before building.
### Step 2: Make the local store the UI's truth
Write to the local database synchronously and reflect it in the UI immediately (optimistic). Never block the UI on a network round-trip. Tag every row with a sync state - pending, syncing, synced, failed - so the UI can show subtle pending indicators and surface failures.… load the full skill through Skill Me