Local-First
What is local-first?
Section titled “What is local-first?”Local-first software stores data on the user’s device as the primary copy. The network is used for synchronization, not access. This is the opposite of the traditional client-server model where data lives on a remote server and the client is a thin view layer.
The key principles
Section titled “The key principles”- Data ownership — Your data lives on your device. You can read, write, and delete it without permission from any server.
- Offline by default — The app works without a network connection. Queries are instant because they read from local storage, not a remote API.
- Sync, not fetch — When a network is available, peers exchange changes directly. There’s no single server that all clients depend on.
- No spinners — Since data is local, reads are synchronous. The UI never shows a loading state for cached data.
- Longevity — If the company behind the software disappears, your data survives. It’s in a local database you control.
How xNet implements this
Section titled “How xNet implements this”xNet stores all data in IndexedDB on the user’s device. When you call useQuery or useNode, you’re reading from a local database — not making a network request.
Traditional app: Client → Server → Database → Server → ClientxNet app: Client → IndexedDB (done)Sync happens in the background via WebSocket connections to a signaling server, which relays messages between peers. The signaling server never stores your data — it only forwards encrypted messages.
The tradeoff
Section titled “The tradeoff”Local-first requires solving conflict resolution. When two users edit the same data offline and then reconnect, the system must merge their changes without data loss. xNet uses two strategies:
- Yjs CRDTs for rich text — character-level merge, no conflicts possible
- Lamport clock LWW for structured data — field-level last-writer-wins with deterministic tie-breaking
These are well-studied algorithms that guarantee all peers converge to the same state, regardless of the order they receive updates.
Why it matters
Section titled “Why it matters”Performance
Section titled “Performance”Reads from IndexedDB take microseconds. Reads from a server take 50-500ms. Local-first apps feel instant because the data is already there.
Reliability
Section titled “Reliability”The app keeps working when the wifi drops, the server goes down, or the user is on a plane. Changes queue up locally and sync when connectivity returns.
Privacy
Section titled “Privacy”Data can be encrypted end-to-end because the server never needs to read it. xNet signs every change with Ed25519 and can encrypt data with XChaCha20-Poly1305 for private content.
User agency
Section titled “User agency”Users own their data in a concrete sense — it’s in a database on their device. They can export it, back it up, or move it to a different app. No vendor lock-in.
Further reading
Section titled “Further reading”- CRDTs — How conflict-free data types work
- Sync Architecture — How xNet syncs peer-to-peer
- Offline Patterns — Building resilient offline UIs