Offline-First for Kenyan Networks: Service Workers, Sync Queues, and Knowing When Not To

S
Samuel Kimani
May 05, 2026 3 min read

Offline-first is not a "nice to have"

For half of our products, offline-first is the difference between "usable" and "abandoned". A field agent doing parcel handovers in Eastleigh, a teacher running Mwalimu.ai in a rural school, a POS clerk in a Kibra carwash, all of them have intermittent connectivity. Software that requires a stable connection is software they will work around using paper.

The architecture, summarized

Three pieces: a service worker that intercepts fetch requests and serves cached responses when offline, an IndexedDB store that holds write-intent (every form submission, every state change), and a background sync queue that drains to the server when connectivity returns. Laravel handles its side with a sync endpoint that accepts batches of operations with timestamps and idempotency keys.The simplest mistake is treating the server as authoritative for reads but the client as authoritative for writes. When the user makes a write, the client commits it to local state immediately (optimistic UI), queues it for sync, and only "settles" the write when the server acks. If the server rejects (conflict, validation), the client surfaces it as a conflict to resolve, not a silent data loss.

Conflict resolution: last-writer-wins is rarely correct

Two agents update the same parcel's status offline. They both come online. Who wins? Last-writer-wins is the default in every library and the wrong answer for almost every domain. A parcel marked "Delivered" by one agent and "Lost" by another should not silently overwrite, it should produce a manual review.Mwalimu.ai uses a domain-specific resolver per entity type. Parcel status uses a state-machine resolver (only transitions allowed by the FSM go through; others queue for human review). Quiz submissions are append-only (every submission is a new row, the server determines which counts). Subscriber profile edits use last-writer-wins with a notification to the other writer. The right answer depends on what the data means.

IndexedDB pragmatics

IndexedDB is the only persistent client storage that handles enough data for serious offline work. It is also famously painful. We wrap it in Dexie for ergonomics and treat it like a real database, explicit schema versions, migrations, and integrity constraints. Every record carries a sync_status field (pending, syncing, synced, conflict) so the UI can render a state without guessing.Storage quotas are real. iOS Safari is the strict one, around 1GB for IndexedDB before the OS starts evicting. Most users will never hit this, but our parcel handover app pulls down route data for the day, and route data is large. We compress aggressively and explicitly purge synced records older than 30 days.

When to skip offline-first entirely

Offline-first is an engineering investment. For an admin dashboard used by a single ops person in a Nairobi office on fiber, it's overkill, you pay the complexity tax for no operational benefit. Our heuristic: if the user does the same task more than twice a week from somewhere that isn't fixed-line internet, build for offline. If it's a desk job in a connected office, build for online and add a clear "you're offline" banner for the edge cases.The cost is real. Our offline-first products run 30-40% more code than their online-only equivalents, and the bug surface is wider. Worth it for the field-agent and rural-classroom use cases; not worth it for the back-office tools where the original assumption was right.

Need software built?

Tell us what you need. We respond within 24 hours with a realistic quote.