Offline-first is not a feature you add later. It is a decision about where your data lives, and it changes the shape of the application from the first schema.
Key Takeaways
- Offline-first is not a feature you add later.
- It is a decision about where your data lives, and it changes the shape of the application from the first schema.
Offline-first means the application writes to local storage first and treats the server as something it reconciles with later. That is the whole idea, and it is why it cannot be added at the end: it changes where your source of truth lives.
In Nepal this matters outside the obvious places. A clinic in a district hospital loses connectivity during a power cut. A delivery rider goes through a valley. A shop's fibre drops for an afternoon. In each case the work does not stop, so the software cannot either.
What "offline-first" actually changes
In a normal web application, a user action sends a request and the UI waits for a response. The server decides what is true. If the request fails, the action failed, and the user tries again.
In an offline-first application, the action is written locally and confirmed immediately. A background process sends it onward when it can. The server is no longer the only thing that decides what is true, and that single change ripples through the design.
Identifiers are the first thing to move. If the server assigns record ids, a device that creates three records offline has nothing to call them. Generate ids on the client, usually UUIDs, so a record has a stable identity from the moment it exists.
Timestamps are the second. Device clocks are wrong more often than people expect, sometimes by hours. Record both the device time and the server's arrival time, and decide which one your ordering rules use.
Conflicts are a product decision, not a technical one
Two nurses update the same patient record on two tablets while both are offline. When they sync, something has to give. Engineers reach for a technical answer here, but the right answer depends on what the data is.
Last-write-wins is easy and appropriate for a draft. It is wrong for a medication list, because the losing write disappears with nobody informed.
Field-level merging keeps both changes when they touch different fields. It works well for records with independent fields and badly for anything where two fields have to agree.
For clinical or financial data, keeping both versions and asking a human is usually correct, even though it is the least satisfying answer. The system's job there is to notice the conflict and present it clearly, not to guess.
Whatever you pick, write it down in the spec and show it in the interface. Users forgive a system that says "this record changed on another device, here are both". They do not forgive one that silently drops an entry.
The sync state has to be visible
The most common complaint about offline-capable software is not that sync failed. It is that the user could not tell. Every screen that shows data should be able to answer: is this current, is it waiting to send, or did something go wrong?
A small, honest indicator is enough. Three states, plain words. "Saved on this device, not yet uploaded" is more useful than a spinner, because it tells the user their work is safe and what is still pending.
Give them a manual retry as well. When connectivity returns and the queue does not move, a button that tries again is the difference between a support call and a shrug.
What to test
The bugs live in the transitions, so that is where the tests go. Kill the network mid-sync and restart the app. Fill the queue with several days of writes and then reconnect. Set the device clock forward an hour. Sync the same record from two devices at once.
None of these happen in a normal test pass, and all of them happen in a district hospital. Running them by hand once before launch is worth more than another week of unit tests on the happy path.
When not to do it
Offline-first costs real time, so it should be a decision rather than a default. If your users are office staff on stable connections, a good loading state and an honest error message will serve them better than a sync engine you now have to maintain.
Do it when the work genuinely continues without a network, and when losing that work has a cost. That is the test. Everything else is a nice-to-have that adds a permanent maintenance burden.
Enjoyed this article? Share it with others!
Written by
AntByte Labs
Engineering · AntByte Labs
AntByte Labs is a Engineering at AntByte Labs, sharing expert insights on technology, software development, and digital innovation to help businesses grow.