Crash Course · 2026 Edition

Local-First, State of the Art

Everything you need to get caught up on local-first software — the theory, the sync-engine landscape, the hard unsolved parts, and how to actually pick a stack for a web or mobile app.

Sources summarized & cross-referenced from awesome-local-first · ~25 min read

01What local-first actually means

The term comes from Ink & Switch's 2019 essay Local-First Software (and Kleppmann et al.'s accompanying paper). The core inversion: the primary copy of your data lives on the user's device, and the server — if there is one — is a sync peer, not the source of truth. The essay defines seven ideals: instant response, multi-device, offline, collaboration, longevity ("your data outlives the app"), privacy, and user control.

It's worth separating three things that get conflated:

Why should an advanced engineer care beyond the ideology? Two reasons that show up over and over in the source material. First, performance: reading from a local store means every interaction is a sub-millisecond query, which is how Linear and Superhuman (the 100 ms rule) feel the way they do. Second, architecture simplification: once a sync engine owns data movement, you delete the entire fetch/cache/invalidate/loading-spinner layer of a conventional app — the argument made in Are Sync Engines the Future of Web Applications? and Riffle's reactive-relational essay.

For balance, read Why Haven't Local-First Apps Taken Off? (2025): the honest answer is that you're taking on distributed-systems complexity (migrations, conflicts, partial replication, auth) that the cloud model centralizes away, and until recently the tooling made you pay that cost yourself. The tooling is what changed — that's most of what this post covers.

02The architecture spectrum

Every local-first system answers the same four questions: where does data live locally, how do writes propagate, who resolves conflicts, and who enforces permissions? The answers place you on a spectrum:

Offline cacheServer-authoritative. Queue writes, replay on reconnect. Trello, most PWAs.
Synced replicaFull/partial local DB, server reconciles. Linear, Zero, Electric, PowerSync.
CRDT documentAny replica merges with any other; server is a dumb relay. Automerge, Yjs, Jazz.
Pure P2PNo server at all. Hypercore/Pear, Iroh, Earthstar, Anytype.

Moving right buys you autonomy and resilience; it costs you central control, easy auth, and simple schema evolution. The single most useful framing in the whole reading list is from You Might Not Need a CRDT: if you have a server anyway, let it be the arbiter and your data structures get radically simpler. Figma famously runs on this principle — per-property last-writer-wins arbitrated by the document server, not a CRDT (How Figma's Multiplayer Works).

Most production systems today sit in the second column, borrow CRDT techniques where cheap (see fractional indexing, below), and reserve full CRDTs for text.

03Conflict resolution: CRDTs, OT, and neither

When two offline devices edit the same data, something must merge the results. Three schools:

Operational Transformation (OT)

The Google Docs approach: transform concurrent operations against each other, usually requiring a central server to sequence them. Mature but notoriously hard to implement correctly — play with the interactive OT visualization to see why. Joseph Gentle, who built OT systems at Google Wave, wrote the definitive conversion story: I Was Wrong. CRDTs Are the Future.

CRDTs

Conflict-free Replicated Data Types: data structures whose merge is commutative, associative, and idempotent — replicas converge no matter what order updates arrive in, no central sequencer required. Start with A Gentle Introduction to CRDTs, then Jake Lazaroff's interactive intro (build a LWW register in ~100 lines), then Matt Weidner's Designing Data Structures for Collaborative Apps for how to think in CRDT primitives. For depth, Bartosz Sypytkowski's 22-post series is the long course.

Two objections have historically kept CRDTs out of production, and both are now largely answered:

Server reconciliation (neither)

The pragmatic third way: clients send intents (mutations), the server applies them in order against authoritative state, clients rebase their optimistic state on the result. This is Figma's model, Linear's model, and the model of Replicache/Zero-style engines. You lose peer-to-peer merges; you gain centralized validation, permissions, and dramatically simpler reasoning.

The trick worth stealingEven non-CRDT systems use fractional indexing for ordered lists — give each item a position key between its neighbors so concurrent inserts don't collide. Liveblocks has the best walkthrough; Figma described the same trick in their multiplayer post.

Rule of thumb distilled from the list: collaborative free-form text → CRDT (Yjs/Loro/Automerge). Structured app data with a server → server reconciliation or a sync engine. True P2P/E2EE requirement → CRDT, because no server can arbitrate what it can't read. James Long's CRDTs for Mortals (with a full reference app) shows the hybrid: plain SQLite + per-column LWW timestamps — the architecture behind Actual Budget.

04The sync-engine landscape

This is where the field moved fastest in 2024–2026. The players cluster into four families:

Postgres-replication engines — keep your backend, sync it down

EngineModelNotes
ElectricSQLPartial replication of Postgres via "shapes" over HTTPRead-path sync engine; writes go through your API. Pairs with PGlite (Postgres-in-WASM) or TanStack DB on the client.
PowerSyncPostgres/MongoDB/MySQL → local SQLite, dynamic sync rulesStrongest mobile story (Flutter, React Native, Kotlin, Swift). Writes via upload queue to your backend.
ZeroQuery-driven sync: client subscribes to ZQL queries, server maintains them incrementallyFrom the Replicache team (Replicache itself is in maintenance mode). Server reconciliation with custom mutators; probably the most-watched engine right now.

Batteries-included platforms — Firebase, but local-first

PlatformModelNotes
InstantDBClient-side triple store, relational queries (InstaQL), optimistic writesOpen-source, hosted or self-hosted; "a Firebase that syncs."
TriplitFull-stack TypeScript sync engine + DBAcquired by Supabase in 2025 — expect its ideas to surface there.
JazzCoValues: CRDT-based collaborative values with built-in auth, permissions, E2EE, sync, and blob storageThe most complete "delete your backend" framework; groups/accounts model handles the auth problem most CRDT stacks punt on.
LiveStoreEvent-sourcing: append-only eventlog, materialized into in-memory SQLite, syncedFrom Johannes Schickling (Prisma founder). Redux-meets-SQLite; strong devtools, web + Expo.

Client-side reactive databases — bring your own sync

LibraryStorageNotes
RxDBIndexedDB/OPFS/SQLite adaptersMature, plugin-heavy; replication protocols for CouchDB, GraphQL, HTTP, WebRTC. Their why-local-first essay is a good sales pitch for the whole space.
TanStack DBIn-memory collections, differential dataflowReactive live queries + optimistic mutations over any sync backend (designed to pair with Electric). The "query layer" piece of the puzzle.
TinyBaseIn-memory, pluggable persistersTiny, dependency-free reactive store with CRDT sync and rich devtools.
Dexie.jsIndexedDBThe veteran IndexedDB wrapper; Dexie Cloud adds sync.
EvoluSQLite (WASM)E2E-encrypted local-first SQLite with sync; type-safe, minimalist, privacy-absolutist.
FireproofBrowser-native, content-addressedMerkle-CRDT ledger DB; sync to any object store.
VerdantIndexedDBStorage + sync + realtime for small apps; built by one dev for his own products, pragmatic and well-documented.

CRDT libraries — the raw material

LibrarySweet spotNotes
YjsCollaborative text/editorsThe industry default; bindings for ProseMirror, CodeMirror, Monaco, tiptap. Servers: Hocuspocus, Y-Sweet, or hosted Liveblocks.
AutomergeJSON documents, versioned dataInk & Switch's library; Rust core, v3 brought ~10× memory reduction. Best-in-class history/branching story.
LoroJSON + rich text + movable treesNewest generation; Rust, fast, time-travel built in.
json-joyJSON + Peritext rich textPerformance-obsessed; powers mu-txt.

Two cross-cutting comparisons are worth reading whole: The Spectrum of Local-First Libraries (Triplit vs Evolu vs Zero vs LiveStore, by DX) and Choosing a Sync Engine in 2026 (first-hand selection war story). Neon's framework comparison and Jared Forsyth's database series add rigor. An emerging thread to watch: Ossa, a 2025 attempt at an open universal sync protocol so apps aren't locked to one engine, and Braid, the IETF draft that would make HTTP itself a sync protocol.

05The local storage layer

Whatever engine you pick sits on one of these substrates:

06P2P & the networking layer

Most apps ship with a sync server, but the fully-decentralized end of the spectrum matured too:

Also file under "infrastructure that made this easier": Cloudflare Durable Objects (a stateful, SQLite-backed object per document — the natural home for a sync/presence server) and PartyKit built on top of them.

07The hard parts

These are the areas where you'll spend your actual engineering budget, and where research is still active:

Auth & permissions without a trusted server

The unsolved-until-recently problem. If any device can write, who enforces "read-only collaborator"? Directions: UCAN (capability tokens built on DIDs — delegation works offline), and Ink & Switch's Beehive (convergent capabilities: access control that merges like a CRDT). Jazz ships a practical groups-based version today; most sync engines instead keep permissions on the server (Zero's queries, Electric's shapes, PowerSync's sync rules).

End-to-end encryption

CRDTs merge on any replica, so they can merge on devices — the server can be a blind relay. Excalidraw's E2EE writeup is the approachable intro; Kerkour's CRDT+E2EE research notes covers the sharp edges; for group key management the standard is now MLS (RFC 9420) with OpenMLS as the Rust implementation. Shipping examples: Jazz, Evolu, Anytype, Standard Notes, Notesnook.

Schema migration

Old clients holding old data must interoperate with new ones — you can't run a Rails migration on someone's phone. Ink & Switch's Project Cambria (bidirectional lenses) is the research answer; in practice engines handle it with additive-only schemas, version-gated sync, or per-document versioning. The CTO's guide covers pragmatic strategies. Ask about this before adopting any engine.

Partial sync at scale

You can't replicate a 10 GB workspace to a phone. Every serious engine has a partiality mechanism — Electric's shapes, Zero's synced queries, PowerSync's sync rules — and Linear's scaling story is the best account of what happens when you get this wrong and have to re-architect live.

Version control for everything

The research frontier: Upwelling (private drafts + real-time collab) and Patchwork (branch/diff/merge for arbitrary apps) point at Git-like workflows over CRDT history — Automerge and Loro already expose the primitives.

08Who runs this in production

Linear — the synced-replica flagshipFull client-side replica (IndexedDB), server-sequenced deltas, lazy partial sync as they scaled. Their writeup is required reading, and their model directly inspired Zero.
Figma — server reconciliation, no CRDTsPer-property LWW arbitrated by a document server, fractional indexing for order, plus a WAL for reliability. Proof that "multiplayer" ≠ "CRDT."
Superhuman — offline-first disciplineLocal store + queued commands, engineered around the 100 ms rule and unreliable networks.
Notion — local SQLite for speed onlyWASM SQLite cache cut navigation times ~20% — local-first techniques adopted piecemeal by a cloud app.
Actual Budget — CRDTs for mortals, shippedOpen-source budgeting: SQLite + per-column LWW CRDT messages, syncable through a dumb server. The best small codebase to actually read.
Anytype / AFFiNE / Excalidraw / tldraw — the native generationP2P + E2EE knowledge OS (Anytype), Yjs-backed workspace (AFFiNE), E2EE collaborative canvases (Excalidraw, tldraw).

09Choosing a stack in 2026

The decision tree, distilled from the comparison posts and case studies above. Start from your constraint, not from a library:

Your situationReach forWhy
Existing Postgres backend, want local-first readsElectricSQL + PGlite/TanStack DBRead-path sync without surrendering your write path or API.
Web app, relational data, real-time multiplayerZero, or InstantDBQuery-driven sync + server-reconciled writes; permissions stay server-side.
Mobile app (RN/Flutter/native), existing backendPowerSyncLocal SQLite, mature mobile SDKs, backend-agnostic writes. (See also Expo's local-first guide.)
Mobile, no backend to keepWatermelonDB, LiveStore (Expo), or Couchbase LiteOn-device-first reactive DBs with sync options.
Greenfield, want zero backend codeJazz, or Triplit-style platformAuth + permissions + E2EE + sync in one model; accept framework lock-in.
Collaborative text/canvas editorYjs (+ Hocuspocus/Y-Sweet/Liveblocks), or Loro/AutomergeThis is the one domain where CRDTs are unambiguously the answer.
Privacy-absolutist / E2EE requiredEvolu, Jazz, or Automerge + your own blind relayServer can't arbitrate what it can't read — you need mergeable data.
No servers, everAutomerge/Loro over Iroh, or Pear runtimeThe full-decentralization stack, now actually practical.
Event-sourced state, auditability, devtoolsLiveStoreEventlog as source of truth, SQLite as a derived view.

And the meta-advice, which nearly every practitioner post converges on:

  1. Decide who arbitrates. Server-reconciled or CRDT-merged is the fork in the road; everything else follows. Default to a server if you have one (you might not need a CRDT).
  2. Model mutations as intents, not state patches — it's what makes optimistic UI, undo, and server validation composable. (Zero's custom mutators, LiveStore events, Actual's messages all encode this.)
  3. Plan partial sync and migrations on day one. These are the two things you cannot bolt on later — Linear re-architected twice.
  4. Steal fractional indexing for anything ordered.
  5. Prototype the sync failure modes early — two devices offline for a week, clock skew, a tombstoned entity edited elsewhere. Superhuman's unreliable-networks post is the checklist.

10Staying current

The field moves monthly. The high-signal feeds:

If you read only five things from this post: the original essay, You Might Not Need a CRDT, Linear's scaling story, The Spectrum of Local-First Libraries, and Choosing a Sync Engine in 2026. That's the theory, the counterweight, the production reality, and the shopping guide — enough to make a defensible architecture call.