Sohail Ahmad
Building Offline-First Mobile Apps with SwiftData
When we built AutoLedger — a vehicle management app for the Indian market — offline-first wasn't a nice-to-have. It was essential. Users track fuel purchases at gas stations with spotty reception. They log maintenance at workshops with no WiFi. The app had to work perfectly without internet.
Here's how we architected it with SwiftData and what we learned along the way.
SwiftData as the Source of Truth
The core principle is simple: SwiftData is the single source of truth. Every user action writes to the local database immediately. The UI always reads from SwiftData. Cloud sync happens in the background as a secondary concern.
This means the app feels instant — no loading spinners, no 'waiting for server' states. Tapping 'Add Fuel Entry' saves to disk in milliseconds. The user sees their updated mileage stats immediately.
Conflict Resolution Strategy
The tricky part of offline-first is handling conflicts. What happens when a user edits a record on their phone while offline, and someone else (or they themselves on another device) edits it online?
For AutoLedger, we use a last-write-wins strategy with timestamps. Every record has an `updatedAt` field. During sync, the newer version wins. This works well for single-user apps where conflicts are rare — usually it's the same person who was offline and then reconnected.
For multi-user apps, you'd want something more sophisticated like CRDTs or operational transforms. But for most consumer apps, last-write-wins is the pragmatic choice.
The Sync Engine
Our sync engine runs on a simple queue: every write operation is also added to a pending sync queue. When connectivity is available, the queue processes in order. If a sync fails, it retries with exponential backoff.
We use Firebase Firestore for the cloud layer because it handles a lot of the sync complexity for us — real-time listeners, offline persistence, and automatic retry. But the key insight is that Firestore is the backup, not the primary database.
Lessons Learned
After shipping AutoLedger with 500+ fuel entries tracked by early adopters, here are our key takeaways: always design the UI to read from local storage first; test with airplane mode as your default state; and keep the sync layer as thin as possible — it should only handle transport, not business logic.
Sohail Ahmad
Founder & Lead Engineer at BlackBuck Solutions
Full-stack architect who leads every project from concept to deployment. Writes about building production software for startups and businesses.
Related articles
Why We Choose Next.js for Every Startup Project
Why Small Agencies Deliver Better Software
Comments
Leave a comment