Local-First Software
Local-first software is an architecture where the primary copy of the user's data lives on their device, and the network is used to sync — not to serve every read and write. The app works instantly and fully offline because it isn't waiting on a server; changes propagate to other devices and collaborators in the background, merging automatically when they reconnect.
This inverts the default of the cloud era, where the server is the source of truth and the client is a thin, latency-bound window onto it. Local-first flips that: the client owns the data, operations are instant because they're local, and sync is an eventual-consistency problem solved with conflict-free data structures. The payoff is software that feels immediate, keeps working without a connection, and still supports real-time collaboration — the combination that made tools like collaborative editors feel magical.
TL;DR
- In local-first apps the device holds the source of truth; the server syncs rather than serves. Reads and writes are instant and local.
- It delivers three things at once: snappy UX (no network round-trip), offline support, and real-time collaboration — historically you had to pick.
- The hard problem is merging concurrent edits from multiple devices. CRDTs (conflict-free replicated data types) solve it: any order of merges converges to the same result, no central coordinator needed.
- Sync engines package this — you write to a local store, they handle replication, conflict resolution, and reconnection.
- The tradeoffs: schema migration, storage limits, and access control are harder when data lives on every device.
- It's a strong fit for collaborative, document-centric, and offline-tolerant apps; a poor fit where the server must be authoritative (banking, inventory, anything with hard global invariants).
Quick Example
The local-first shape: writes go to a local store and return immediately; a CRDT-backed sync engine replicates in the background. Conceptually:
The user never sees a spinner on their own edits, and two people editing offline both keep their changes when they sync.
Core Concepts
The Local-First Ideals
The term comes from a set of ideals: the software should be fast (no network round-trip on interaction), work offline, support collaboration, last for the long term (data outlives any one company's servers), be private and secure by default, and give users ownership and control of their data. Not every app hits all of them, but they define the target — and most reduce to the same architectural move: put the data on the device and treat sync as a background concern.
The Central Problem: Merging Concurrent Edits
If two devices can both write while offline, they will produce divergent states. The naive fixes are bad: "last write wins" silently discards work; locking to prevent concurrency defeats the point (you can't edit offline if you need a lock). Local-first needs a merge strategy that:
- Accepts concurrent, offline edits from any number of devices.
- Converges — every device that has seen the same set of changes ends up in the same state, regardless of the order they arrived.
- Requires no central coordinator to resolve conflicts.
That's exactly what CRDTs provide.
CRDTs (Conflict-Free Replicated Data Types)
A CRDT is a data structure designed so that concurrent updates can be merged automatically and deterministically. The formal property is that merges are commutative, associative, and idempotent — apply the same changes in any order, any number of times, and you get the same result. Practically, this means two replicas that have exchanged all their changes are guaranteed to agree, with no conflict resolution UI and no server arbitration.
CRDTs come in flavors for different data: counters, sets, maps, ordered lists (for text and arrays), and rich-text structures. Libraries like Yjs and Automerge implement them as ready-to-use document types, so you manipulate a normal-looking object and the CRDT handles convergence underneath.
💡 Tip: CRDTs guarantee that everyone converges to a consistent state — not that the merged result is what a human would have chosen. For prose, a converged merge can still read oddly; CRDTs solve consistency, not editorial intent.
Sync Engines
Writing CRDT plumbing, persistence, and network reconnection by hand is a lot. A sync engine packages it: you write to a local store (often backed by a CRDT), and the engine handles local persistence, replication to a server or peers, conflict-free merging, and catch-up after reconnection. Sync engines (ElectricSQL, Zero, Replicache, PowerSync, Automerge/Yjs-based stacks) are what make local-first practical for ordinary product teams rather than distributed-systems specialists.
Architecture in Practice
A typical local-first app has these pieces:
The server's role shrinks from "authority that serves every read/write" to "relay and durable backup that helps devices exchange changes." The UI reads and writes the local store synchronously; sync happens off the critical path.
Best Practices
Reach for a Sync Engine, Not Raw CRDTs
Unless you're building infrastructure, use an existing sync engine or CRDT library (Yjs, Automerge, ElectricSQL, Zero, Replicache). They've solved persistence, reconnection, and edge cases you'll otherwise rediscover painfully. Rolling your own distributed merge layer is a research project.
Plan Schema Migration From Day One
Data lives on every device, possibly for years, across app versions. A client that's been offline for months will sync an old-schema document. Design for forward and backward compatibility: additive schema changes, versioned documents, and migration logic that runs on sync. This is the hardest ongoing cost of local-first — budget for it.
Keep Server-Authoritative Concerns on the Server
Not everything should be local-first. Anything requiring a hard global invariant — unique usernames, account balances, inventory counts, payment authorization — needs a server as the source of truth. Use local-first for the collaborative, document-shaped parts of the app and keep authoritative operations server-side. Hybrid is normal.
Mind Storage and Data Volume
Every device holds (at least a subset of) the data. For large datasets, sync a partial replica (the documents this user needs) rather than everything, and prune old CRDT history. Unbounded local growth eventually hits device limits.
Design Access Control Deliberately
When data replicates to devices, "who can see what" can't be enforced by simply not sending rows from a trusted server — the data may already be local. Enforce access at the sync boundary (the server decides which documents a device is allowed to replicate) and consider end-to-end encryption for privacy-sensitive local-first apps.
Common Mistakes
Last-Write-Wins as a "Merge Strategy"
Making Everything Local-First
Trying to make an inventory count or an account balance eventually-consistent across offline devices invites double-spends and impossible states. Keep hard-invariant data server-authoritative; reserve local-first for collaborative, document-centric content.
Ignoring Schema Evolution
Shipping v2 with a changed data shape and no migration path means old-schema documents from long-offline devices corrupt or fail to sync. Version documents and handle migration at sync time from the start.
FAQ
What makes software "local-first"?
The device holds the primary copy of the data, so reads and writes are instant and work fully offline; the server syncs changes rather than serving every operation. This gives snappy, offline-capable apps that also support real-time collaboration — a combination that server-authoritative architectures struggle to deliver at once.
What is a CRDT and why do I need one?
A CRDT (conflict-free replicated data type) is a data structure whose concurrent updates merge automatically and deterministically — any order of merges converges to the same state with no central coordinator. You need one because local-first apps let multiple devices edit offline, and CRDTs are how those divergent edits reconcile without losing work or needing manual conflict resolution.
Local-first vs offline-first — same thing?
Related but not identical. Offline-first means the app keeps working without a connection (often with a queue that syncs later). Local-first is stronger: the device owns the data as the source of truth, giving instant local operations, offline support, and conflict-free multi-device collaboration. Every local-first app is offline-capable, but not every offline-first app is local-first.
When should I not use local-first?
When the server must be the authority for correctness — banking balances, inventory, unique constraints, payment authorization, anything with a hard global invariant that can't tolerate divergent offline states. Also reconsider for huge datasets that can't fit on-device, or strict access-control requirements. Many apps are hybrids: local-first for collaborative content, server-authoritative for the rest.
What's a sync engine?
A sync engine is the layer that makes local-first practical: you write to a local store (often CRDT-backed) and it handles local persistence, replicating changes to a server or peers, merging concurrent edits, and catching up after reconnection. It packages the distributed-systems work so product teams don't have to build it from scratch.
Related Topics
- Event-Driven Architecture — Change propagation and eventual consistency patterns
- System Design — Where local-first fits among architectural choices
- WebSockets — A common transport for real-time sync
- Scalability — How local-first shifts load off the server
- PWA — Offline-capable web apps, a natural home for local-first
- State Management — The client-side store local-first data lives in
- WebRTC — Peer-to-peer sync without a central relay