Podcast: Rethinking Data: Moving From the Traditional Three-Tier Web Stack to Client-Side Event Sourcing
Johannes Schickling ยท rss ยท 2026-07-27 source โ Reader ๐ฅ๏ธ
Client-side event sourcing โ replaying an immutable log of events rather than syncing a mutable, auto-merging CRDT object โ is a structurally different but equally legitimate way to achieve local-first software's goals, and should be adopted (like local-first itself) only when an application's core value genuinely depends on offline resilience, client-side speed, and user data ownership, since restructuring where and how data lives is one of the most fundamental and hardest-to-reverse decisions a team can make.
practical ยท mixed โ A first-person narrative (Prisma -> Overtone -> LiveStore) grounds an argumentative core: when and how to adopt local-first architecture, and which of two competing technical strategies (CRDTs vs. client-side event sourcing) to use to implement it. The theoretical distinction between event sourcing and CRDTs is ultimately in service of practical advice ('adopt local-first only if X; then choose technology Y').
Structure
| Part | Role |
|---|---|
| Personal narrative: founding Prisma as server-side database tooling, then stepping away in 2020 to explore local-first via Ink & Switch. | context |
| The local-first value proposition: matching native-desktop-grade UX by moving the interaction loop and primary data copy to the client. | context |
| Case study: Overtone (a music-curation app) and LiveStore, choosing client-side event sourcing over CRDTs, with SQLite made reactive as the materialized view. | evidence |
| Direct comparison of event sourcing vs. CRDTs as two structurally different but equally valid local-first data models. | core argument |
| Decision framework: when to adopt local-first at all (offline criticality, data-ownership importance, local-vs-global stakes) and how to decompose a monolithic data model into small syncable units. | conclusion / practical guidance |
| Data portability and schemas as the mechanism for genuine user data ownership, including GDPR's incidental role in creating portable-export infrastructure. | extension |
Key terms
- Local-First Local-First Software
A design principle where the client (not the server) holds the primary copy of data and processes changes immediately, giving offline access and no-round-trip speed โ distinct from mere 'offline mode' bolted onto a cloud-first app. - Client-side event sourcing Client-Side Event Sourcing
Treating the client's source of truth as an append-only, ordered log of events (not a mutable object), which is replayed to derive materialized state (e.g. a reactive local SQLite database); lets application logic evolve and be reapplied to full history rather than mutating state in place. - CRDT (conflict-free replicated data type) Local-First Software
In Schickling's framing, a mutable-object abstraction (object, array, set, counter) with automatic, deterministic merge semantics across replicas โ contrasted against event sourcing's append-only, replay-based model. - LiveStore
Schickling's open-source local-first framework combining a client-side event-sourcing sync engine with a reactive, in-process SQLite database as the queryable materialized view; the successor to the Riffle research project (with Nicholas Schiefer and Geoffrey Litt). - Local vs. global (as an adoption heuristic)
A heuristic for deciding whether local-first is appropriate: applications where speed/UX for a single user's own data is paramount (a personal note) favor local-first; applications where cross-user correctness is paramount (a financial transfer, a global social network) favor a traditional authoritative-server model.
Propositions
- explicitThe traditional three-tier web stack (centralized database + API tier + client tier) caps achievable user experience below what well-built native desktop or mobile software delivers.conf: high
- explicitChanging where and how an application's data lives and flows is one of the hardest and highest-leverage architectural decisions a team can make โ harder than swapping databases or web servers.conf: high
- explicitLocal-first's core promise is shifting the primary data copy and the interaction loop to the client, not merely adding offline support to an otherwise cloud-first app.conf: high
- explicitNot every application benefits from local-first; adoption should be justified per-app by whether offline resilience and data ownership are core to that app's value, not treated as a default upgrade.conf: high
- explicitClient-side event sourcing โ an append-only log of events replayed to derive state โ is a viable alternative to CRDTs for achieving local-first's goals, trading a different set of complexities for a different set of guarantees.conf: highextendsPodcast: Increasing Users' Data Agency: From BlueSky's AT Protocol to the Local-First Software Movement ยท p14 โ Extends Kleppmann's CRDT/Automerge-centric account of how local-first is realized by presenting client-side event sourcing as a structurally different, equally valid mechanism for the same goals.
- explicitEvent sourcing suits data that is messy, externally sourced, and needs schema evolution over time better than CRDTs, because new application logic can be applied by replaying full history rather than mutating an object in place.conf: high
- explicitCRDTs remain a sufficient and often simpler foundation when data types are simple (counters, sets, GitHub-label-style toggles) and merge semantics are not order-sensitive.conf: high
- explicitA local-first app's client-side speed can be combined with centralized durability by treating the sync backend purely as a backup/propagation channel rather than as the authoritative source of truth.conf: high
- explicitLocal-first fits domains where the user is the author/owner of their own data (a personal library, personal notes) and is a poor fit for data with an inherently authoritative external source of truth, such as a global financial system.conf: highsupportsPodcast: Increasing Users' Data Agency: From BlueSky's AT Protocol to the Local-First Software Movement ยท p15 โ Reinforces Kleppmann's claim that local-first fits user-authored data but not data with an authoritative external source, adding a concrete local-vs-global heuristic (personal notes vs. a global financial system) for applying it.
- implicitRetrofitting an existing application's data layer to local-first after the fact is far more costly than designing it in from the start.conf: mediumsupportsPodcast: Increasing Users' Data Agency: From BlueSky's AT Protocol to the Local-First Software Movement ยท p16 โ Schickling's own account of leaving Prisma's server-centric architecture behind and rebuilding from scratch (rather than retrofitting) is a first-person confirmation of Kleppmann's claim that retrofitting to local-first is hard when logic already lives server-side.
- explicitDecomposing a monolithic centralized data model into small, independently syncable units (e.g. per-issue, per-canvas) is a necessary precondition for local-first to scale.conf: high
- explicitWhether an app's data can be cleanly decomposed into bounded units (vs. an all-connected social-network graph) is itself a signal of whether local-first is a good fit.conf: high
- explicitGenuine data ownership for a local-first app's users requires exposing a durable, legible source-of-truth artifact (the event log plus the materialized database), not just a one-off export dump.conf: high
- explicitRich, well-designed schemas โ not AI alone โ are what makes messy, multi-source external data (e.g. music metadata from many services) usable and portable over time.conf: high
- implicitGDPR's mandatory data-export requirement, though not designed for this purpose, inadvertently created reusable infrastructure for bootstrapping local-first or otherwise portable applications.conf: medium
Arguments
Client-side event sourcing is a legitimate, and for some applications superior, alternative to CRDT-based local-first architectures. strength: medium
Explicit premises:
- Event sourcing lets a team replay history under new application logic rather than mutating an object in place.
- Music-library metadata is messy, externally sourced from multiple changing services, and needs long-term schema evolution and de-duplication/tombstoning.
- CRDTs are built around a mutable-object abstraction that is harder to reason about semantically when the data's shape and provenance keep changing.
Implicit premises:
- Auditability and replayability are worth more, for this class of application, than the merge-conflict-free simplicity CRDTs offer.
- The team is willing to absorb event sourcing's higher upfront architectural design cost.
Inferences:
- Teams building on messy, multi-source data more broadly (not only music curation) may be better served by event sourcing than CRDTs, even outside a strictly local-first context.
Teams should adopt local-first architecture only after actively trying to talk themselves out of it. strength: high
Explicit premises:
- Local-first requires substantially more upfront thinking about how data is decomposed and how it will grow.
- The choice of data architecture is a foundational, hard-to-reverse decision, unlike swapping a web router or web server.
Implicit premises:
- Most teams underestimate the cost of switching architectures after the app is built.
- Unneeded architectural complexity carries a real ongoing cost even in a version that technically 'works.'
Inferences:
- A short pre-commitment checklist (offline criticality, tolerance for poor connectivity, importance of user data ownership, whether the data model decomposes into bounded units) should precede any local-first technology selection.
Narratives
- Schickling's arc from founding Prisma (server-centric database tooling) through a self-described 'technological trauma' over database migrations, to going all-in on local-first in 2020 via ideas from friends at Ink & Switch.
โ Grounds the claim that hands-on pain with schema/migration management on the server side is what makes event sourcing's replay-based schema evolution personally and professionally attractive to him โ supports proposition 6 and argument 1 with lived motivation rather than abstract preference. - Overtone's handling of a track Spotify removes from its catalog: Schickling keeps a 'tombstone' preserving all the user's own tags, so that if the same track later reappears from another source it can be de-duplicated and reunited with its history.
โ Concretely illustrates proposition 6 (event sourcing's suitability for messy, externally-sourced, evolving data) and gives operational meaning to 'data ownership' beyond the bare fact of local storage. - The comparison to Uber's database growing from small per-city deployments to a globally scaled system, forcing repeated backend data-architecture rework โ which Schickling frames as 'easier' than the equivalent local-first rework because it stayed purely a backend concern.
โ Supports propositions 2 and 4 (adoption should be deliberate) โ illustrates why the same kind of growth-driven rearchitecture becomes comparatively harder and higher-stakes once it has to happen on the client, as local-first requires.
Questions addressed
- โ
How can a web application achieve the perceived reliability and speed of native desktop software?
By moving the primary data copy and the change-processing loop to the client (local-first) instead of routing every interaction through a server. - โ
Should a local-first app use CRDTs or event sourcing to implement its data sync?
Depends on the data type and its provenance: simple, order-insensitive data (counters, sets) suits CRDTs; messy, schema-evolving, externally-sourced data suits event sourcing. - โ
How does a local-first app preserve genuine user data ownership and portability if the user wants to leave?
By exposing the raw event log and/or materialized database as a legible, well-schema'd artifact rather than an opaque one-off export dump. - โญ Is client-side event sourcing viable, or even superior, for real-time multi-user collaborative editing โ the scenario CRDTs were specifically designed for?
Gaps
- incompleteSchickling advocates client-side event sourcing as a general alternative to CRDTs for local-first, but never explains how event sourcing handles concurrent conflicting writes from multiple simultaneous devices or users โ the central problem CRDTs were explicitly designed to solve. LiveStore's actual conflict-resolution model for genuinely concurrent multi-writer scenarios is left unaddressed; every concrete example he gives (Overtone) is single-user.
Read next: LiveStore's own documentation/RFCs on multi-client concurrent writes and conflict resolution; Martin Kleppmann's 'Turning the Database Inside Out' talk, which Schickling names as event sourcing's intellectual ancestor. - incompleteThe claim that event sourcing suits 'messy, externally sourced data' better than CRDTs is illustrated only by a single-user personal-curation app (Overtone tombstoning a removed Spotify track); no comparison is offered for how a CRDT-based app would actually handle the same de-duplication/tombstoning problem, so it remains unclear whether the advantage is inherent to event sourcing or specific to LiveStore's schema design.
Read next: A syntopical read against Kleppmann's own account of what CRDTs/Automerge can and cannot represent well (extract-kleppmann-data-agency-local-first). - uninformedSchickling states LiveStore is 'still not fully production-ready' but never specifies which production gaps remain (performance at scale, missing tooling, security review, etc.), leaving open exactly how close it is to a safe choice for teams evaluating it today.
Read next: LiveStore's public roadmap/issue tracker for current production-readiness status.
Closes gaps elsewhere
- Podcast: Increasing Users' Data Agency: From BlueSky's AT Protocol to the Local-First Software Movement ยท g4 โ Partially answers the gap's 'merge semantics that need not match user intent' concern about CRDTs: Schickling explains his reason for moving away from CRDT-style mutable objects toward event sourcing is precisely that mutable data makes it hard to trace where a change came from and to reason about what should semantically happen โ engaging directly with that specific cost, though not with the gap's other sub-points (storage overhead, loss of server-side authoritative validation).