WhollySoftware
Back to blogMobile

Offline-First Architecture for Mobile Apps with Unreliable Networks

Wholly Software TeamJanuary 8, 20257 min read
Offline-First Architecture for Mobile Apps with Unreliable Networks

A construction-inspection client came to us with an app that technically supported offline mode but in practice lost data constantly, because 'offline support' meant caching a few API responses and hoping. Field inspectors working in basements and remote sites were losing entire inspection reports whenever connectivity dropped mid-submission. We rebuilt the data layer around a local-first architecture instead of retrofitting caching onto an online-first app.

The core decision was to make the local database — Room on Android, a Core Data-backed store bridged into our shared Kotlin Multiplatform layer — the single source of truth for the UI. Every write goes to the local store first and returns immediately, then a background sync worker pushes changes to the server. The UI never waits on a network call to reflect a user's action, which alone eliminated the most common inspector complaint.

Sync conflicts turned out to be the hard part, not offline storage itself. We used a last-writer-wins strategy with a server-side timestamp for most fields, but for inspection photos and checklist items specifically we needed field-level merging, since two inspectors occasionally worked the same site. We ended up building a small operational-transform-style merge for the checklist state rather than reaching for a general CRDT library, which was overkill for our actual conflict patterns.

Sync reliability required its own retry design. We use exponential backoff with jitter for the sync worker, capped at a 15-minute interval, plus a foreground 'sync now' action so inspectors regaining signal aren't stuck waiting on the backoff timer. WorkManager on Android and BGTaskScheduler on iOS handle the background half; neither platform's guarantees are strong enough to rely on alone, so we pair background sync with an explicit sync-on-foreground trigger.

The unglamorous part was surfacing sync state honestly to users. We added a persistent, unobtrusive status indicator showing pending vs. synced items, because the previous app's silent failures were what actually broke trust — inspectors didn't mind spotty connectivity, they minded not knowing whether their work was saved.

Six months post-launch, failed submissions dropped from roughly 12% of inspections to under 0.3%, and that number is almost entirely accounted for by devices that were never reopened with connectivity before the retention window closed.

Offline-FirstSyncMobile ArchitectureAndroidiOS
Offline-First Architecture for Mobile Apps with Unreliable Networks — Wholly Software