Optimistic UI is not enough.
We've all written the code: setShow(true), then fetch('/api/create'). If the fetch fails, we revert the UI.
But what if the user is offline for 3 days? What if they close the tab before the fetch completes? What if they make 50 edits while in a tunnel?
Local-First is not just "caching." It means the Client Database is the source of truth for the UI. The Server is just a backup.
Deep Dive: The 100ms Threshold
Jakob Nielsen's rule: < 100ms feels instantaneous.
Server roundtrips vary (50ms - 500ms). Local-First guarantees < 10ms for all read/write operations by hitting the local DB first.
02. Sync Engine Architecture
In a Local-First app, you never `await fetch()` in your component's event handler.
The Sync Queue
Your application needs a robust queueing system.
- Mutation: A user action (e.g., "Add Todo") is serializable into a JSON instruction.
- Persist: Save this instruction to IndexedDB immediately.
- Apply: Run the logic against the local state for instant feedback.
- Push: A `navigator.onLine` listener attempts to flush the queue to the server.
- Rebase: If the server rejects it (conflict), re-calculate the state.
03. Conflict-Free Replicated Data Types (CRDTs)
When two users edit the same document offline, and then come online, who wins?
CRDTs are data structures that guarantee mathematical consistency.
Last-Write-Wins (LWW)
Simple, brute force.
User A sets title "Hello" at 10:00.
User B sets title "Hi" at 10:01.
Sync -> Title is "Hi".
Grow-Only Set (G-Set)
Perfect for Todo Lists.
You can only ADD items. Removing is strictly "Adding a tombstone". Merging two lists is just the union of both.
04. The Modern Stack
Replicache
Commercial grade sync engine. Handles the queue, the websocket, and the optimistic UI for you. Used by linear.app style apps.
PGLite (Postgres in Wasm)
Run a full Postgres database inside the browser tab. Sync it to a real server-side Postgres via logical replication.
ElectricSQL
An open-source layer that sits between your Postgres and your clients, managing active replication streams.
06. Build: Offline-First Todo
Try this simulation. Turn "Off" the network switch. Add items. Reload the page (simulating a crash). Then turn the network back "On" and watch the sync happen.