Many of the users I build for in India are on patchy mobile networks: farmers, traders, staff at coaching centres. "Works offline" gets thrown around a lot, so this post separates two things that often get confused, and is honest about which one I've actually built.
Level 1: offline-capable caching (what I've shipped)
In FaceClass, the attendance tablet app, I used Hive to keep members, face data and recent attendance on the device. Screens open from local data, and on-device face recognition works without the network.
Writes, though, go to the server first. A check-in is recorded locally only after the API confirms it. That keeps the server the single source of truth and avoids conflicts entirely, but it also means no network, no new records.
This is the right trade-off for many apps, and it's what most "offline support" really is: fast, resilient reads with online writes.
Level 2: true offline-first (what it would take)
Offline-first means the app accepts writes while offline and reconciles them later. It's much harder, and it's a design I'd use for field workflows like listings or data collection:
UI → local write (Hive) → durable outbox → sync worker → API → ack → mark synced
↑ |
└──────────── conflict / retry ←────────────────┘
The pieces that make it work:
- Client-generated IDs on every mutation, so a retried sync can't create duplicates, plus a server-side unique constraint to enforce it
- A durable outbox that survives the app being killed, drained by a sync worker when connectivity returns
- An explicit conflict policy per entity. Last-write-wins is fine for a profile field, but it's dangerous for anything involving money or bids
- Honest UI states: offline, syncing, conflict, failed. Never pretend something is saved on the server when it isn't
- Require-online for money-adjacent actions. Bids and payments shouldn't be queued offline at all, because being wrong costs more than a spinner does
Practical lessons from building with local caches
- Cap the cache. Low-end Android phones have little storage, so evict by entity type and age
- Normalise heavy inputs before upload. On NestIQ I downscale and re-encode photos on-device, in a background isolate, before upload, which makes uploads smaller and more reliable on slow networks
- The server stays authoritative unless you've designed the conflict rules
Takeaway
Know which level you're building. A good local cache with server-first writes is simple and robust. True offline-first is an architecture decision about sync and conflicts, and Hive is just the storage underneath it.