Build the mental model
Every app storing data locally is making several architectural decisions at once — storage type, offline behavior, sync reconciliation — and the underlying concepts are the same across every framework.
| Concept | Explanation |
|---|---|
| Local Storage | Suits preferences, cached data, and drafts — nothing catastrophic happens if it's lost. |
| Secure Storage | Needed for authentication tokens/credentials — a platform-provided mechanism like Keystore/Keychain. |
| Caching | Store remote data locally, display it instantly, then quietly refresh in the background. |
| Offline Mode | Falls back to the local cache instead of a blank error screen when the network is unavailable, where supported. |
Sync is the hardest concept — two offline changes to the same data can conflict, making it more complex than "just upload when online."
- Secure Storage
- A platform-provided mechanism — like Android's Keystore-backed encrypted storage or iOS's Keychain — designed to store sensitive data (tokens, credentials) in a way that resists extraction.
- Conflict Resolution
- The strategy (last-write-wins, server-authoritative, merge, manual) used to decide which version wins, or how to combine them, when two changes to the same data conflict.
OFFLINE-FIRST DATA FLOW
-----------------------
OFFLINE-FIRST DATA FLOW
-----
Local change made (e.g. edit a note)
|
v
Add change to sync queue
|
v
Network available? ----No----> Use local cache, retry later
|
Yes
|
v
Sync queued changes to server
|
v
Conflicts found? ----No----> Local cache updated, done
|
Yes
|
v
Resolve (last-write-wins / server-authoritative / merge / manual)Connect it to a real scenario
Suppose a notes app has the same note edited offline from a phone and also from a laptop — when it reconnects, the app faces a real conflict.
| Strategy | Tradeoff |
|---|---|
| Last-Write-Wins | Simple, but can silently discard real work that isn't the newest timestamp. |
| Server-Authoritative | Safe for consistency, but frustrating for a user who loses a local edit. |
| Merge | Auto-combines non-conflicting parts; manual resolution asks the user to choose instead. |
No single strategy is correct for every app — a to-do app might accept last-write-wins, while a collaborative document tool needs merge-based sync.
Try the working example
function chooseStorageType(data) {
const { isSensitiveCredential, isUserPreference, isCachedContent } = data;
if (isSensitiveCredential) return "secure storage (Keychain/Keystore-backed)";
if (isCachedContent) return "cache (fetched remote data, safe to lose or refetch)";
if (isUserPreference) return "normal local storage";
return "normal local storage (default for uncategorized local data)";
}
const authToken = { isSensitiveCredential: true, isUserPreference: false, isCachedContent: false };
const fetchedArticleList = { isSensitiveCredential: false, isUserPreference: false, isCachedContent: true };
const darkModeSetting = { isSensitiveCredential: false, isUserPreference: true, isCachedContent: false };
const unsavedDraftNote = { isSensitiveCredential: false, isUserPreference: false, isCachedContent: false };
console.log("Auth token:", chooseStorageType(authToken));
console.log("Fetched article list:", chooseStorageType(fetchedArticleList));
console.log("Dark mode setting:", chooseStorageType(darkModeSetting));
console.log("Unsaved draft note:", chooseStorageType(unsavedDraftNote));Auth token: secure storage (Keychain/Keystore-backed)
Fetched article list: cache (fetched remote data, safe to lose or refetch)
Dark mode setting: normal local storage
Unsaved draft note: normal local storage (default for uncategorized local data)
Only the sensitive credential routes to secure storage, while cached content routes to the cache category specifically.5-minute try-it
Add a fifth boolean, `isDraftContent`, to `chooseStorageType`, and decide for yourself: should a draft go in the same bucket as cached content, or does it deserve its own answer? Update the function to match your reasoning.
One important caution
Storing authentication tokens or credentials in plain generic local storage instead of secure storage
Assuming "just upload when online" is enough and never planning a conflict-resolution strategy
Data synchronization — Wikipedia — How Mobile Apps Work