Skip to content

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.

  1. Data ownership — Your data lives on your device. You can read, write, and delete it without permission from any server.
  2. Offline by default — The app works without a network connection. Queries are instant because they read from local storage, not a remote API.
  3. Sync, not fetch — When a network is available, peers exchange changes directly. There’s no single server that all clients depend on.
  4. No spinners — Since data is local, reads are synchronous. The UI never shows a loading state for cached data.
  5. Longevity — If the company behind the software disappears, your data survives. It’s in a local database you control.

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 → Client
xNet 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.

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.

Reads from IndexedDB take microseconds. Reads from a server take 50-500ms. Local-first apps feel instant because the data is already there.

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.

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.

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.