Search selfstore
v1.8.22

Blog

Engineering notes on local-first storage. No growth hacks, no listicles: the same voice as the docs, on questions that deserve more room.

What happens when the user opens a second tab

A server app serialises writes at the database. A local-first app has no such point, and every user eventually opens the app twice. The four ways that goes wrong, and the three browser primitives that fix it.

There is no password reset

A "forgot password" link is a statement about who holds the key. An app that encrypts on the client cannot offer one - so recovery has to be designed at the moment the password is chosen, not at the moment it is lost.

Browser storage is not durable storage

IndexedDB can be deleted without asking you - under disk pressure, after seven days of Safari inactivity, or with one click in the settings. What an app can actually find out about its own storage, and what it should do with the answer.

An export button is not portability

Every app has an export. Almost none of them let you leave. The difference is whether the file is readable without the software that wrote it - and there is a short test that settles it.

Schema migrations when you do not hold the database

Local-first inverts who owns the data, and with it who can run a migration. What replaces the deploy-time script - a read-time upgrade, a version that travels with the file, and a loud refusal in the other direction.

Designing an interface when the network is optional

Offline-first deletes most of the UI states a server app needs - spinners, retry toasts, optimistic rollback - and adds three smaller obligations in their place.

Why IndexedDB is the right working copy for a local-first app

A local database as the app's live state - not a server round-trip, not localStorage - and the separation between a working copy and a durable home that makes it safe.

Local-first is a security posture, not just a privacy feature

The largest breaches are server-side. Keeping one person's data on their own device removes a whole class of them - and here is exactly which class, and which threats it does not touch.

Encrypted backups in the browser, done right

What client-side encryption actually protects against, why AES-256-GCM over Argon2id, and why a format spec beats a vendor promise.

Your side project does not need a backend (yet)

An honest decision tree for when a web app actually needs a server - and how far durability, backups and multi-device sync go without one.

Multi-device sync without a sync server

Storage-as-mailbox, hybrid logical clocks and per-collection merge strategies - how deterministic convergence works when nobody runs a server.