Skip to content
Back to blog

Local-First Is Having a Moment

CRDTs, sync engines, offline-capable apps. The local-first movement is getting practical.

architecture local-first sync

What local-first means

Your data lives on your device. It syncs to other devices and to a server, but the local copy is the source of truth. If the server goes down, your app keeps working. If you’re on a plane, your app keeps working. If the company behind the app shuts down, you still have your data.

This isn’t new as an idea. Git works this way. But building apps like this was hard enough that most people didn’t bother. That’s changing.

What changed

A few things happened at once. CRDTs (conflict-free replicated data types) went from academic papers to usable libraries. Yjs, Automerge, and ElectricSQL made it possible to build collaborative, offline-capable apps without rolling your own sync logic.

Linear uses a local-first architecture. Figma is local-first for collaboration. These aren’t obscure indie projects. Production apps with millions of users are proving this works.

Sync engines like PowerSync and ElectricSQL let you point at a Postgres database and get local-first sync without rewriting your backend. I tried PowerSync with one of my projects. Setup took an afternoon. The app feels noticeably faster because reads hit a local SQLite database instead of making network requests.

Why I think about this as a PM

Local-first apps feel fast in a way that server-dependent apps can’t match. No loading spinners for reads, no optimistic UI hacks. The data is already there.

Users in bad network conditions (subway, rural areas, developing countries) get the same experience as users on fiber. Most product teams don’t think about this enough.

And users keep their data. I think more people will start expecting that.

What’s still hard

Permissions and access control get complicated when you can’t rely on the server as the gatekeeper. If a user gets removed from a shared document, you need to handle that across all synced devices.

Conflict resolution works great for text (CRDTs handle this well) but gets tricky for structured data. Two users editing different fields of the same record is fine. Two users editing the same field at the same time requires decisions about who wins.

Storage on device is limited compared to a server. You can’t local-first a dataset with millions of rows without some kind of partial sync strategy.

Where I’m going with this

My next side project will be local-first from day one. I want to build something with ElectricSQL and see how the development experience compares to the typical client-server approach. I suspect it’s faster to build with once you get past the initial learning curve.