InfoQ
Unlike consensus algorithms that discard conflicting inputs or cloud architectures that require centralized coordination, formally verified CRDTs guarantee replica convergence across decentralized networks by preserving all concurrent operations.
AI-assisted summary of CRDTs and the Quest for Distributed Consistency — original source. Check the original for full context.
Source published:
Key ideas
- Collaborative editing relies on convergence rather than consensus; while distributed consensus picks a single winner to discard conflicting operations, CRDTs retain and merge all concurrent mutations into an identical final state. (14:11)
- Traditional Operational Transformation (OT) suffered from two decades of flawed convergence proofs before stabilizing into centralized, server-bound implementations like Google Docs that preclude direct local-network synchronization. (9:55)
- Kleppmann's team used the Isabelle interactive theorem prover to formally verify that CRDT implementations (including RGA, OR-Sets, and counters) satisfy Strong Eventual Consistency under adversarial network conditions. (17:26)
- Automerge translates standard imperative JSON modifications into an append-only operation log using ES6 proxies, retaining full edit history to facilitate Git-like branching and time-travel state reconstruction. (20:02)
Detailed notes
## Background Presented at QCon London 2018 and published on YouTube by InfoQ on October 2, 2018, this lecture features Martin Kleppmann exploring distributed consistency in decentralized environments. The presentation details algorithms and data structures that allow multiple users to collaborate on shared documents over peer-to-peer networks and sync devices locally without routing data through remote cloud servers.
## TL;DR Kleppmann contrasts consensus mechanisms—which pick a single winner to prevent double-spending—with collaborative convergence, where systems preserve and merge all concurrent edits. After examining the historically error-prone evolution of Operational Transformation (OT) and its reliance on central servers, he introduces Conflict-free Replicated Data Types (CRDTs) as a robust, mathematically verified alternative supporting offline-first and decentralized workflows. He details how his team used the Isabelle interactive theorem prover to formally verify algorithms like RGA under adversarial network conditions, ensuring Strong Eventual Consistency. Finally, Kleppmann breaks down Automerge, an open-source JavaScript JSON CRDT library, demonstrating how append-only operation logs, stable character IDs, and skipping traversal rules resolve complex concurrent edits in practice.
## Atmosphere & style Kleppmann delivers the talk with measured academic rigor, understated humor, and accessible engineering pragmatism, establishing a grounded tone early on by noting he is lecturing while actively on strike against university pension cuts. The narrative balances formal mathematical verification via theorem provers with intuitive developer touchpoints, moving effortlessly between Git mental models, collaborative grocery lists, and pixel art prototypes. Watching the presentation feels demystifying and intellectually refreshing, turning abstract distributed systems theory into practical, tangible architecture.
## Bulletin - [14:11](https://www.youtube.com/watch?v=B5NULPSiOGw&t=851s) Collaborative editing relies on convergence rather than consensus; while distributed consensus picks a single winner to discard conflicting operations, CRDTs retain and merge all concurrent mutations into an identical final state. - [09:55](https://www.youtube.com/watch?v=B5NULPSiOGw&t=595s) Traditional Operational Transformation (OT) suffered from two decades of flawed convergence proofs before stabilizing into centralized, server-bound implementations like Google Docs that preclude direct local-network synchronization. - [17:26](https://www.youtube.com/watch?v=B5NULPSiOGw&t=1046s) Kleppmann's team used the Isabelle interactive theorem prover to formally verify that CRDT implementations (including RGA, OR-Sets, and counters) satisfy Strong Eventual Consistency under adversarial network conditions. - [20:02](https://www.youtube.com/watch?v=B5NULPSiOGw&t=1202s) Automerge translates standard imperative JSON modifications into an append-only operation log using ES6 proxies, retaining full edit history to facilitate Git-like branching and time-travel state reconstruction.
## Key takeaways - [01:17](https://www.youtube.com/watch?v=B5NULPSiOGw&t=77s) Convergence in collaborative applications guarantees that all replicas eventually reflect identical state once updates sync, differing fundamentally from distributed consensus. - [02:26](https://www.youtube.com/watch?v=B5NULPSiOGw&t=146s) Local-first distributed architectures apply edits immediately to local storage to eliminate latency and maintain an offline-capable mutation queue that flushes upon reconnection. - [06:30](https://www.youtube.com/watch?v=B5NULPSiOGw&t=390s) Conflict resolution across distinct data structures requires recording operation intent rather than simple point-in-time value comparisons. - [09:55](https://www.youtube.com/watch?v=B5NULPSiOGw&t=595s) Operational Transformation spent nearly two decades plagued by algorithms that failed to ensure convergence due to subtle concurrency edge cases. - [12:49](https://www.youtube.com/watch?v=B5NULPSiOGw&t=769s) Correct Operational Transformation implementations mandate a centralized server to serialize and transform operations, preventing direct peer-to-peer syncing between proximal devices. - [14:11](https://www.youtube.com/watch?v=B5NULPSiOGw&t=851s) Blockchains and distributed consensus mechanisms are designed to select a single valid branch to prevent double-spending, directly contrasting with collaborative data types that preserve all concurrent edits. - [17:26](https://www.youtube.com/watch?v=B5NULPSiOGw&t=1046s) Mathematical verification via the Isabelle proof assistant was employed to guarantee that CRDT algorithms hold Strong Eventual Consistency across arbitrary message reorderings, delays, and drops. - [20:02](https://www.youtube.com/watch?v=B5NULPSiOGw&t=1202s) Automerge is a JavaScript library modeling nested JSON data structures that abstracts CRDT convergence mechanics away from application-level logic. - [20:48](https://www.youtube.com/watch?v=B5NULPSiOGw&t=1248s) Prototype applications Trellis and Pixel Pusher demonstrate that CRDTs can power complex collaborative interactions like serverless Kanban boards and asynchronous branch merges. - [23:59](https://www.youtube.com/watch?v=B5NULPSiOGw&t=1439s) Automerge remains agnostic to the underlying network transport, working interchangeably over WebRTC data channels, the Dat project's Hypercore protocol, or traditional WebSockets. - [25:12](https://www.youtube.com/watch?v=B5NULPSiOGw&t=1512s) JavaScript ES6 proxies allow developers to manipulate Automerge state through familiar mutable syntax while automatically generating fine-grained, immutable CRDT operations under the hood. - [28:55](https://www.youtube.com/watch?v=B5NULPSiOGw&t=1735s) Retaining a complete append-only log of micro-operations eliminates the immediate need for complex compaction routines and provides built-in time-travel state inspection. - [32:15](https://www.youtube.com/watch?v=B5NULPSiOGw&t=1935s) When concurrent scalar field updates conflict, Automerge deterministically selects one display value while preserving competing inputs inside an `_conflicts` metadata object for custom resolution. - [35:42](https://www.youtube.com/watch?v=B5NULPSiOGw&t=2142s) Sequence CRDTs prevent position shifting during concurrent text editing by assigning unique composite identifiers (counter plus node ID) to each character rather than numeric array indexes. - [40:33](https://www.youtube.com/watch?v=B5NULPSiOGw&t=2433s) Deterministic traversal rules that compare character identifiers ensure that concurrent text insertions at identical document locations reach consistent ordering across all nodes.
## Detailed walkthrough ### [00:04](https://www.youtube.com/watch?v=B5NULPSiOGw&t=4s) Introduction and Industrial Action at UK Universities
Martin Kleppmann introduces himself and notes that the audience may recognize him as the author of *Designing Data-Intensive Applications*, published roughly a year earlier. He clarifies immediately that his book is not focused on Conflict-free Replicated Data Types (CRDTs), but rather provides a wide-ranging examination of large-scale data system architectures and distributed systems challenges. Shifting to his current role, he explains that he is a researcher at the University of Cambridge, though with an unusual caveat: on this particular day, he is formally on strike.
He explains the context behind the labor action, describing a nationwide dispute occurring across numerous universities in the United Kingdom over plans by institutional leadership to radically slash employee pensions. Kleppmann characterizes this policy as an unjustified, massive pay cut. He decided to deliver his scheduled conference presentation despite the strike because the dispute is strictly with university management rather than the organizers or audience at QCon. However, he emphasizes the personal nature of his appearance: “just to say that I am giving this talk as a private individual who happens to be interested in distributed systems rather than [an official university representative].”
[01:17](https://www.youtube.com/watch?v=B5NULPSiOGw&t=77s) Convergence in Collaborative Systems vs. Consensus
Diving into the technical content, Kleppmann frames the session around collaborative applications, using Google Docs as the quintessential real-world example. In these systems, multiple participants edit a shared document simultaneously without relying on an awkward exchange of files over email. The primary operational objective in these environments is convergence: despite several users modifying the document concurrently, every participant's screen must eventually display identical contents once their edits propagate and sync.
Kleppmann contrasts this goal with consensus, referencing Heidi Howard's morning talk on the topic. While both consensus and convergence superficially seek distributed agreement among nodes, Kleppmann asserts that their underlying mechanics and computational guarantees diverge significantly. As he puts it: “Actually this is a very different kind of problem even though it looks superficially similar the properties that it has are fundamentally different and comparing those two will be an interesting part of this talk.”
```mermaid flowchart TD accTitle: Comparing Convergence and Consensus accDescr: High-level contrast between consensus protocols and convergence in collaborative editing.
subgraph ConsensusApproach["Consensus (e.g., Paxos / Raft)"] A["Node Proposal"] --> B["Global Coordination Round"] B --> C["Single Agreed-upon Order"] end
subgraph ConvergenceApproach["Convergence (e.g., CRDTs)"] D["Local Mutation Applied Instantly"] --> E["Asynchronous Replication"] E --> F["Independent Merging to Identical State"] end ```
[02:26](https://www.youtube.com/watch?v=B5NULPSiOGw&t=146s) Local-First Edits, Git Merges, and Offline Work
To build intuition around concurrency, Kleppmann outlines the familiar workflow of software developers working with Git. A programmer edits source files locally, saves them to disk, commits them, and eventually pushes them to a remote repository like GitHub. In parallel, a coworker may alter the same repository and push their work first. When the second developer pulls, Git attempts to reconcile the histories. If the developers modified separate files or distant sections of the same file, Git merges the changes cleanly without intervention; if their edits touch the exact same lines, the system halts with a merge conflict that demands manual resolution.
Kleppmann points out that distributed nodes—whether laptops, smartphones, or data center servers—follow this exact model: - Edits are committed immediately to the node's local storage copy (such as a hard drive or the browser tab's memory). - Local mutations take effect instantly to eliminate typing lag, avoiding any round-trip delay to a centralized server. - Updates are forwarded asynchronously in the background across the network to peers or coordinating servers. - When an offline event or network partition occurs, mutations remain queued locally until connectivity is re-established, after which all accumulated changes flush out to be merged.
[06:30](https://www.youtube.com/watch?v=B5NULPSiOGw&t=390s) Conflict Resolution Across Common Data Types
While Git often demands human judgment when edits overlap, web applications like Google Docs eliminate manual merge dialogs entirely, resolving conflicts automatically using predefined algorithmic heuristics. Kleppmann demonstrates how intuitive rules can produce sensible merged outcomes across three distinct data types:
```mermaid flowchart LR accTitle: Merge Examples Across Data Types accDescr: Visualizing merge resolution for text, sets, and counters under concurrent mutations.
subgraph TextMerge["1. Text Document Merge"] T0["'hello!'"] -->|"User 1 inserts 'world '"| T1["'hello world!'"] T0 -->|"User 2 inserts ':-)'"| T2["'hello!:-)'"] T1 & T2 --> TM["'hello world!:-)'"] end
subgraph SetMerge["2. Set Merge (Add-Wins)"] S0["{ A, B }"] -->|"User 1 removes B"| S1["{ A }"] S0 -->|"User 2 adds C"| S2["{ A, B, C }"] S1 & S2 --> SM["{ A, C }"] end
subgraph CounterMerge["3. Counter Merge"] C0["Value = 1"] -->|"User 1 increments (+1)"| C1["Value = 2"] C0 -->|"User 2 increments (+1)"| C2["Value = 2"] C1 & C2 --> CM["Value = 3"] end ```
1. **Text Documents**: - Initial state: `"hello!"` - User 1 adds `"world "` right before the exclamation mark (`"hello world!"`). - User 2 adds a smiley `":-)"` right after the exclamation mark (`"hello!:-)"`). - Merged result: Google Docs preserves both localized insertions based on their positioning relative to the exclamation point, yielding `"hello world!:-)"`.
2. **Unordered Sets**: - Initial state: `{A, B}` - User 1 removes element `B`, leaving `{A}`. - User 2 concurrently adds element `C` via set union, producing `{A, B, C}`. - Merged result: Because element `A` was untouched, element `B` was explicitly discarded, and element `C` was freshly introduced, the correct synthesized outcome is `{A, C}`.
3. **Counters**: - Initial state: `1` (such as a social media post's like count). - User 1 and User 2 both trigger an increment, each locally computing a transition from `1` to `2`. - Merged result: Simply taking the latest state value of `2` would silently lose an operation. Kleppmann highlights that correct reconciliation requires tracking the underlying intent of the mutations: “So what this is saying is that we need to consider not just the state the value at any one time because if we just compare two and two they look the same but actually we need to capture the sequence of changes that were made to the data and we apply those and that will allow us to reach a sensible merged outcome.” Preserving both distinct increment actions leads to the correct end state of `3`.
[09:55](https://www.youtube.com/watch?v=B5NULPSiOGw&t=595s) The Troubled History of Operational Transformation and the Emergence of CRDTs
The challenge of multiple users editing shared state simultaneously and automatically merging their edits has been studied by academics since the late 1980s. Historically, two distinct families of algorithms have tackled this problem. The first is Operational Transformation (OT), which serves as the foundational algorithm underlying Google Docs. However, academic and practical frustration with OT grew significantly during the early 2000s due to subtle, persistent design flaws. This frustration spurred a new direction of academic research centered around Conflict-free Replicated Data Types (CRDTs), which became the focus of Martin Kleppmann's research group.
Kleppmann recounts the historical trajectory of OT as an alarming cycle of published proofs and subsequent refutations. Early papers appeared logical and theoretically sound on the surface, but researchers repeatedly discovered years later that the proposed algorithms were flat-out wrong. In the context of collaborative editing, an algorithm is considered wrong if it fails to achieve convergence—the guarantee that all participants arrive at an identical document state once all concurrent edits have ceased. Instead, subtle concurrency edge cases caused document states to diverge permanently, leaving replicas hopelessly out of sync. Successive researchers attempted to repair these bugs with new OT variants, only to have their revised algorithms broken in follow-up literature a few years later. Martin Kleppmann described this two-decade academic cycle as:
> “So over the course of about two decades all of these algorithms were proposed and then of only a few later few years later to discover that it's wrong so a real bloodbath of failed algorithms here.”
Eventually, a handful of provably correct OT algorithms were established, one of which powers Google Docs today. However, these correct variants carry a severe structural limitation: they strictly mandate a centralized server. All client communications must flow through this central authority, which dictates global ordering. Clients are forbidden from exchanging changes over direct side channels or ad-hoc backchannels, as doing so violates the fundamental invariants required to preserve convergence.
- Operational Transformation (OT) academic research began in the late 1980s. - OT's primary failure mode was subtle concurrency edge cases resulting in permanent divergence between replicas. - Correct OT algorithms require a strict star topology around a centralized server to serialize and transform operations.
---
[12:49](https://www.youtube.com/watch?v=B5NULPSiOGw&t=769s) Centralized Client-Server Limitations vs. Decentralized Topologies
Kleppmann highlights how absurd the centralized restriction becomes in everyday usage scenarios. Even if two devices—such as a user's smartphone and laptop—are resting 50 centimeters apart on the same desk, syncing data between them currently requires round-tripping traffic through a remote data center in Virginia. Kleppmann argues that collaborative systems should instead support arbitrary, decentralized communication topologies.
```mermaid flowchart TD accTitle: Centralized Client-Server vs Decentralized Peer-to-Peer accDescr: Contrasts the centralized Google Docs OT architecture against a decentralized CRDT model that supports local-network synchronization.
subgraph Centralized ["Centralized Architecture (Google Docs / OT)"] S["Central Cloud Server (e.g., Virginia)"] C1["User A (Phone)"] <-->|"Must route all edits"| S C2["User A (Laptop)"] <-->|"Must route all edits"| S C3["User B (Device)"] <-->|"Must route all edits"| S end
subgraph Decentralized ["Decentralized Architecture (CRDTs)"] P1["User A (Phone)"] <-->|"Local Wi-Fi / Bluetooth (50 cm)"| P2["User A (Laptop)"] P2 <-->|"Opportunistic P2P / Internet"| P3["User B (Device)"] P1 -.->|"Eventual sync via Internet"| P3 end ```
Under a decentralized model, two devices belonging to the same user or local collaborators should synchronize directly over a local network, Bluetooth, or whatever ambient connectivity is available, without requiring an active Internet uplink. When full Internet connectivity is re-established later on, those nodes should seamlessly synchronize outward with other remote peers. This model is impossible under standard Google Docs-style operational transformation due to its reliance on a central coordinator.
- Centralized OT forces all edits through remote servers, precluding offline local-network collaboration. - Decentralized synchronization accommodates dynamic network partitions, ad-hoc peer connections, and delayed Internet re-convergence.
---
[14:11](https://www.youtube.com/watch?v=B5NULPSiOGw&t=851s) CRDTs vs. Blockchains: Why Consensus Differs from Collaboration
Because Kleppmann advocates for decentralized architectures, he notes that audiences inevitably ask whether his work is related to blockchains. The blockchain space frequently uses the term "decentralization" to describe systems that eliminate reliance on a trusted central coordinator. While acknowledging the valid cryptographic foundations of blockchains, Kleppmann explains that blockchains and collaborative document editors solve fundamentally opposing problems.
A blockchain links successive blocks using cryptographic hashes, allowing participants to verify the integrity of the chain and use structures like Merkle trees to verify individual records. Blockchains utilize Byzantine fault tolerant consensus algorithms to achieve an agreed-upon, totally ordered, linear sequence of blocks without forks. This strong consensus mechanism is engineered specifically to prevent double-spending in cryptocurrencies by selecting one transaction when conflicting spends are proposed and discarding the other. In contrast, collaborative editing requires preserving concurrent contributions rather than picking a single winner. Kleppmann makes this sharp distinction:
> “So what we want here for collaboration protocols is to keep all of the changes that were made and to merge them in such a way that they converge towards the same state so that is what I mean with this thing look superficially like consensus and is really different because consensus is fundamentally around this idea of choosing one.”
| Dimension | Blockchain / Distributed Consensus | Collaborative Data Types (CRDTs) | |:--- |:--- |:--- | | **Core Abstraction** | Consensus / Total Order | Convergence / Partial Order Merging | | **Handling Conflicts** | Chooses *one* valid proposal; rejects/discards conflicting alternatives | Merges *all* concurrent modifications into a shared state | | **Primary Use Case** | Preventing double-spending (cryptocurrency transactions) | Collaborative authoring, multi-device data synchronization | | **Structural Output** | Single, non-forking linear chain of cryptographic blocks | Replicated, deterministic data structures (text, sets, counters) |
---
[17:26](https://www.youtube.com/watch?v=B5NULPSiOGw&t=1046s) Formal Verification of CRDTs Using Isabelle
CRDTs are multi-master data structures that allow multiple nodes to apply concurrent modifications independently and merge states deterministically without central arbitration. They have already emerged in production tools: the Atom text editor introduced a collaborative editing feature powered by CRDTs, and the distributed database Riak adopted CRDTs internally to resolve conflicting concurrent object writes.
Mindful of the twenty-year history of flawed proofs in Operational Transformation, Kleppmann’s team sought absolute mathematical rigor before putting new algorithms into production. Rather than relying on informal reasoning and intuition—which had repeatedly failed OT researchers—the team used the Isabelle interactive theorem prover to mechanize their proofs and establish correctness.
Kleppmann and his colleagues formalized multiple CRDT specifications inside Isabelle: - **RGA (Replicated Growable Array):** A CRDT designed for ordered sequence operations, such as concurrent rich-text editing. - **Observed-Remove Set (OR-Set / AWSet):** A collection data type supporting concurrent item additions and removals. - **P-N Counter:** An increment/decrement distributed counter data type.
Their proofs operate across a two-layered verification architecture. At the top layer, they proved that these CRDT implementations satisfy *Strong Eventual Consistency* (SEC), which formally guarantees convergence across replicas without central coordination. At the bottom layer, they verified the system assumptions against an adversarial network model. This network model simulates realistic distributed conditions by arbitrarily delaying, duplicating, reordering, or dropping messages. The Isabelle machine proofs verified that the necessary safety and consistency assumptions hold across all possible execution paths of this unreliable network model, ensuring that network degradation cannot break CRDT convergence guarantees.
- **Theorem Prover:** Isabelle was used to author and check end-to-end formal proofs. - **Target Invariant:** Strong Eventual Consistency (SEC), which implies deterministic convergence across all replicas. - **Verified Data Structures:** RGA for concurrent text editing, sets (OR-Set), and distributed counters. - **Network Resilience:** The algorithms were mathematically proven to remain consistent despite arbitrary message drops, delays, and reorderings.
[20:02](https://www.youtube.com/watch?v=B5NULPSiOGw&t=1202s) Automerge: A JSON-like CRDT Data Structure Library
Martin Kleppmann transitions from the theoretical verification of CRDT algorithms to practical engineering, introducing Automerge. Automerge is an open-source JavaScript library developed to realize these algorithms in practice. While the concepts can be implemented in any language, JavaScript was chosen because of its broad portability across web browsers, desktop environments, and mobile platforms. Kleppmann describes Automerge as a foundational data model layer or data structure library upon which developers can build collaborative client applications.
The core abstraction offered by Automerge mirrors a standard JSON document. Applications interact with and modify this tree-like document structure, while the underlying library automatically handles tracking edits and resolving concurrent changes across peers.
```mermaid flowchart TD accTitle: Automerge Architecture Overview accDescr: Shows how applications sit on top of the Automerge CRDT abstraction layer, which in turn plugs into diverse network layers.
subgraph AppLayer["Application Layer"] Trellis["Trellis (Kanban Board)"] PixelPusher["Pixel Pusher (Pixel Art)"] CustomApp["Custom JSON Apps"] end
subgraph CoreLayer["Data Model Layer"] Automerge["Automerge CRDT Engine<br/>(Immutable State / Operation Log)"] end
subgraph NetLayer["Pluggable Networking Layer"] MPL["MPL (WebRTC Peer-to-Peer)"] Hypermerge["Hypermerge (Dat / Hypercore)"] Sockets["WebSockets / Central Server"] end
Trellis --> Automerge PixelPusher --> Automerge CustomApp --> Automerge Automerge <--> MPL Automerge <--> Hypermerge Automerge <--> Sockets ```
- Automerge provides a JSON-like interface composed of nested lists and key-value maps. - The library runs as a self-contained in-memory process without imposing a mandatory backend architecture. - Developers can write client software against standard local operations without managing distributed conflict resolution manually.
---
[20:48](https://www.youtube.com/watch?v=B5NULPSiOGw&t=1248s) Prototype Applications: Trellis and Pixel Pusher
To validate Automerge in real-world scenarios, the team developed prototype collaborative applications. The first of these is Trellis, a peer-to-peer clone of the popular project management tool Trello. Trellis implements columns and cards that users can drag and drop, assign to individuals, and annotate with comments. The system functions entirely without centralized servers: updates and card movements are broadcast peer-to-peer over WebRTC data channels. On the interface, an activity log records and displays every modification made by collaborating users.
```mermaid flowchart LR accTitle: Pixel Pusher Collaboration and Branching Model accDescr: Illustrates how an original pixel art document can branch into variants and merge back like a pull request.
subgraph Versioning["Pixel Pusher Document History"] BaseDoc["Base Document<br/>(Eyeballs)"] BranchA["Variant A<br/>(Potato Man)"] BranchB["Variant B<br/>(Alternative Art)"] MergedDoc["Merged Local Document"] end
BaseDoc -->|"Fork / Suggest"| BranchA BaseDoc -->|"Fork / Suggest"| BranchB BranchA -->|"User accepts & merges"| MergedDoc ```
The second prototype is Pixel Pusher, an interactive, collaborative pixel art editor built on top of an existing browser-based implementation by Xavier Balan. Beyond standard concurrent editing—where drawing a pixel immediately reflects on a collaborator's canvas—Pixel Pusher experiments with asynchronous collaboration workflows reminiscent of Git pull requests or Google Docs suggesting mode. The user interface allows collaborators to maintain divergent document variants—for instance, one branch adding a "potato man" body onto an initial canvas showing only eyeballs—and switch between them. Users can inspect these proposals and selectively merge an external variant into their local canvas. Kleppmann notes:
> “So these kind of things are enabled simply by keeping track of the history of all of the changes that are done and that is what Automerge does internally.”
- **Trellis:** Replicates Kanban-style workflows over serverless WebRTC data channels using a custom networking package called MPL. - **Pixel Pusher:** Built on top of an open-source single-user pixel editor by Xavier Balan, adapted to explore branching, variant switching, and lightweight merges. - **History tracking:** Keeping an immutable log of edits allows applications to render audit logs and branch document states seamlessly.
---
[23:59](https://www.youtube.com/watch?v=B5NULPSiOGw&t=1439s) Pluggable Networking: WebRTC, Dat/Hypercore, and WebSockets
Kleppmann clarifies that Automerge does not contain a built-in networking layer. Instead, it is purely a JavaScript data structure library running inside a single local process. It leaves the transport mechanism entirely to the developer, allowing diverse network topologies to be swapped in underneath.
For Trellis, the team paired Automerge with WebRTC using a support library named MPL to achieve direct browser-to-browser peer communication. For Pixel Pusher, they experimented with the peer-to-peer Dat project ecosystem, creating an integration layer called Hypermerge that bridges Automerge with Dat's append-only log primitive, Hypercore. Kleppmann emphasizes that developers are by no means restricted to peer-to-peer stacks; traditional client-server setups using WebSockets or simple HTTP endpoints are equally compatible, as Automerge is agnostic to how serialized update payloads move across the wire.
- Automerge is deliberately unopinionated about network transports. - **MPL:** A utility library used in Trellis to route CRDT operation payloads over WebRTC channels. - **Hypermerge:** An integration package tying Automerge to the Dat project's Hypercore append-only log abstraction. - Traditional client-server transports (e.g., standard WebSockets) work out of the box by ferrying serialized Automerge updates between clients.
---
[25:12](https://www.youtube.com/watch?v=B5NULPSiOGw&t=1512s) The JSON Data Model and Automerge's API Design
The data modeling philosophy of Automerge revolves around standard JSON primitives, which consist of two primary compositional mechanisms: lists (ordered sequences of elements) and maps (dictionaries associating string keys to values). Because lists and maps can be arbitrarily nested, they can represent complex application states—such as a to-do list where items contain titles, completion flags, and subtasks. Manipulations on this state include setting boolean flags, updating strings, inserting or removing elements in lists, and assigning new dictionary keys.
```mermaid flowchart TD accTitle: Automerge State Transition and Proxied Mutation accDescr: Flowchart tracing an immutable state object through the change callback into fine-grained micro-operations and a new immutable state.
subgraph API["Application Code"] CurrentState["Current State (Immutable)"] ChangeCall["Automerge.change(state, 'Add to-do item', callback)"] ProxyDoc["doc.todos.push({ title: '...', done: false })<br/>(Intercepted via ES6 Proxy)"] NewState["New State (Immutable)"] end
subgraph Engine["Automerge Internal Engine"] OpLog["Generated Operations: 1. MakeMap(new_id) 2. SetKey(new_id, 'title', 'Buy milk') 3. SetKey(new_id, 'done', false) 4. InsertListItem(list_id, pos, new_id) 5. LinkMapToList(list_id, pos, new_id)"] end
CurrentState --> ChangeCall ChangeCall --> ProxyDoc ProxyDoc --> OpLog OpLog --> NewState ```
In Automerge, document states are treated as immutable objects, heavily inspired by libraries like Immutable.js. When updating data, the application calls `Automerge.change`, passing in the previous state and an updater callback function. To avoid awkward functional update syntax, Automerge provides an imperative programming experience within the callback: it supplies a mutable proxy handle to the document via JavaScript ES6 Proxy objects. When code performs standard JavaScript mutations—such as calling `doc.todos.push(...)`—the proxy intercepts the mutation and translates it into discrete operational events. Callbacks can also take an optional, human-readable commit message string describing the intent of the change.
Behind the scenes, high-level array pushes or object assignments are decomposed into granular micro-operations: creating an empty map entity, populating each property key (`title`, `done`), allocating an insertion slot in the containing list, and linking the new map's identifier to that slot. Kleppmann remarks:
> “Fortunately you don't have to ever write these kind of operations yourself that would get extremely tedious but this is just to [give] an idea of what's going on internally.”
- **State immutability:** Application state is never mutated in place; invoking `Automerge.change(currentState,...)` produces a fresh state reference. - **Proxy interception:** Standard JavaScript calls like `.push()` or direct property assignments (`doc.todos[0].done = true`) are converted into atomic CRDT operations under the hood. - **Commit metadata:** Users can attach arbitrary string messages to updates, mirroring Git commit messages for human audits.
---
[28:55](https://www.youtube.com/watch?v=B5NULPSiOGw&t=1735s) Operation Logs, Storage Pragmatism, and Time Travel
Automerge stores and preserves every atomic micro-operation permanently in an internal append-only operation log. While storing complete operation histories incurs a storage cost, Kleppmann defends this approach by drawing a direct comparison to distributed version control systems:
> “And so if Git can keep all history forever then so can we.”
Rather than prematurely adding complicated log compaction routines, the team adopted the pragmatic stance that full history retention is practical and performs surprisingly well on modern hardware, leaving garbage collection and compaction for future revisions.
Retaining full operation history provides significant practical advantages, most notably built-in "time travel" debugging and inspection. Because the document's historical evolution is never discarded, an application can query the log for past states at any prior point in time. Automerge can produce the complete chronological sequence of states that the document traversed since inception, complete with the human-readable commit messages attached to each change.
- All micro-operations are appended to an internal log and preserved indefinitely. - The Git-like storage philosophy eliminates the immediate need for aggressive log pruning while maintaining rich collaboration semantics. - Time travel functionality is an organic consequence of the append-only design, allowing instant materialization of past document revisions.
[29:55](https://www.youtube.com/watch?v=B5NULPSiOGw&t=1795s) Concurrent Changes, Offline Updates, and Convergence
Automerge reconstructs historical document snapshots by selecting the relevant subset of operations recorded up to that point in time and calculating the resulting document state. This operational model leads directly into the core challenge of real-time collaboration: resolving concurrent edits. Martin Kleppmann illustrates this with a shared to-do list initially containing a single item: watering the plants, marked as not done (`done: false`). Two users—such as Kleppmann and his wife syncing between two phones—make offline updates concurrently. Kleppmann adds a new task, buying milk (`done: false`), while his wife completes the plant-watering task, toggling `done` to `true`.
```mermaid flowchart TD accTitle: Concurrent Edits and Convergence accDescr: Independent offline modifications on two separate nodes merge into an identical final state.
subgraph Initial["Initial Shared State"] Init["Task: Water plants (done: false)"] end
subgraph Concur["Concurrent Offline Edits"] NodeA["Node A (Martin)<br/>Adds: 'Buy milk' (done: false)"] NodeB["Node B (Wife)<br/>Sets: 'Water plants' -> done: true"] end
subgraph Merged["Converged State (Both Devices)"] Final["1. Water plants (done: true)<br/>2. Buy milk (done: false)"] end
Init --> NodeA Init --> NodeB NodeA --> Merged NodeB --> Merged ```
Each user sees their local updates applied immediately, ensuring a responsive offline-first experience without requiring server connectivity. When the devices eventually reconnect, Automerge exchanges the operations. Because these changes target different entities—inserting a distinct item versus updating an existing property—they combine cleanly. This brings about the central guarantee of Conflict-free Replicated Data Types (CRDTs): convergence. As Kleppmann defines it: “if any two devices any two nodes have seen the same set of updates or the same set of operations even if they might have seen those operations in a different order as soon as they've seen the same set of operations then the state of the document will also be the same.” This property decouples consistency from the order in which individual nodes observe network messages.
---
[32:15](https://www.youtube.com/watch?v=B5NULPSiOGw&t=1935s) Resolving Conflicts in Fields and Text Editing
While disjoint operations merge seamlessly, certain concurrent updates create conflicts that cannot be unified automatically. The most fundamental conflict occurs when two users concurrently overwrite the same object field or list item with differing values—such as one user editing the task to read "buy soy milk" while the other sets it to "buy almond milk." Because Automerge remains agnostic about dietary preferences, it cannot determine which value is objectively correct. To handle this, it deterministically picks one value as the default display value while storing the alternative in an `_conflicts` metadata object. This records the conflicting node ID (e.g., node `1234`) and the competing value, allowing application developers to build custom user interfaces for manual conflict resolution if desired.
Concurrent text edits, however, do not require manual intervention. Kleppmann shows how Automerge mirrors the behavior of production systems like Google Docs when text overlaps. Suppose a document contains the string `"hey guys"`, and two users attempt to make the phrase gender-neutral at the same time: one replaces `"guys"` with `"everyone"`, while the other replaces `"guys"` with `"folks"`. Automerge treats a double deletion of `"guys"` as a single deletion. For the insertions, both strings are preserved and placed sequentially in an arbitrary, deterministic order based on node identifiers—producing either `"hey everyone folks"` or `"hey folks everyone"`. As Kleppmann points out when defending this automatic merge behavior: “The basis on which we are going here is that actually like Google Docs does this and millions of people use Google Docs so it seems to be fine in many cases.” He suggests that instead of blocking user workflows, systems could simply provide an advisory warning when edits occur within a close proximity threshold (such as 20 characters), alerting users to check whether the resulting sentence remains grammatically coherent.
- Field conflicts assign one deterministic winner while retaining alternates in an `_conflicts` sub-object for manual resolution. - Deletions are idempotent: deleting a character or word on two replicas concurrently yields the same result as deleting it once. - Concurrent insertions at the same location preserve both inputs rather than dropping data, ordering them by node identifier.
---
[35:42](https://www.youtube.com/watch?v=B5NULPSiOGw&t=2142s) The Algorithm: Character Identifiers and Concurrent Insertions
To reveal the internal mechanics of a sequence CRDT, Kleppmann explains how characters are identified without relying on unstable index offsets. In a document reading `H E L O`, each character is assigned a unique identifier consisting of a monotonically increasing counter and a node identifier, such as `1a`, `2a`, and `3a`. If node `a` inserts a second `L` to spell `"hello"`, it assigns the new character an identifier of `4a` and records the insertion point relative to its predecessor (`insert L with ID 4a after 2a`). Concurrently, node `b` appends an exclamation mark, generating the operation `insert! with ID 4b after 3a`. Rather than stating `"insert at position 4"`, pointing directly to stable character IDs ensures that insertions remain valid regardless of how other edits shift the text buffer across the network.
```mermaid flowchart LR accTitle: Unique Character Identification in Sequence CRDTs accDescr: Characters are addressed by stable pairs of counters and node IDs rather than shifting array indices.
subgraph Text["Document State: 'H E L O'"] C1["'H'<br/>ID: 1a"] --> C2["'E'<br/>ID: 2a"] C2 --> C3["'L'<br/>ID: 3a"] C3 --> C4["'O'<br/>ID:?"] end
subgraph OpA["Node A Operation"] InsL["Insert 'L' (ID: 4a)<br/>after 2a"] end
subgraph OpB["Node B Operation"] InsEx["Insert '!' (ID: 4b)<br/>after 3a"] end
C2 -.->|target| InsL C3 -.->|target| InsEx ```
The algorithm faces a trickier challenge when two users insert text at the exact same position. Kleppmann sets up an example starting with the string `A B C`. Node `a` inserts `X` and `Y` between `A` (ID `1a`) and `B`, yielding `A X Y B C`. Independently, node `b` inserts `P` (ID `4b`) and `Q` (ID `5b`) at the same junction between `A` and `B`. When node `a` receives node `b`'s operations, applying them relative to `1a` places `P` directly after `A`, followed by `Q`, resulting in `A P Q X Y B C`. However, when node `b` receives node `a`'s edits, a naive insertion of `X` directly after `1a` would produce a divergent order (`A X Y P Q B C`). To guarantee convergence, the algorithm enforces a tie-breaking traversal rule: incoming operations start at their target predecessor (`1a`) and advance past concurrently inserted characters until finding the correct deterministic insertion point.
- Character IDs pair a local counter with a node identifier (e.g., `4a`, `4b`), making every element across all peers globally unique. - Operations reference predecessor IDs rather than numeric array indexes, keeping insertions resilient against shifting text boundaries. - Resolving concurrent insertions at identical positions requires a deterministic scan rule to prevent peers from interleaving or reversing concurrent strings.
[40:33](https://www.youtube.com/watch?v=B5NULPSiOGw&t=2433s) Resolving Concurrent Text Edits with ID-Based Skipping Rules
Martin Kleppmann walks through the exact mechanics of resolving concurrent list insertions in a text CRDT without losing convergence. When an incoming operation arrives to insert a new character, its identifier must be compared against the identifier of the next element in the list. Specifically, if the incoming operation's ID is less than the next element's ID, the algorithm skips over that element and advances further to the right. In the worked example, the incoming character `X` has the ID `4a`. Looking at the next element, `P` with ID `4b`, `4a` is less than `4b`, so the pointer skips over `P`. The algorithm then evaluates the following element, `Q` with ID `5b`. Because `4a` is also less than `5b`, the rule triggers again: skip over any elements bearing a greater ID than the one being inserted. Only when the comparison reaches element `B` (ID `2a`) does the skipping cease, since `2a` is less than `4a`. Consequently, `X` is inserted precisely at that point.
```mermaid flowchart TD accTitle: CRDT List Insertion Traversal accDescr: Step-by-step traversal comparing incoming ID 4a against elements 4b, 5b, and 2a to find insertion spot.
Start["Incoming op: Insert 'X' with ID 4a"] --> Cmp1{"Compare with next: 'P' (ID 4b)"}
subgraph S1["Skip Greater IDs"] Cmp1 -->|"4a < 4b (Skip)"| Cmp2{"Compare with next: 'Q' (ID 5b)"} Cmp2 -->|"4a < 5b (Skip)"| Cmp3{"Compare with next: 'B' (ID 2a)"} end
subgraph S2["Stop and Place"] Cmp3 -->|"4a > 2a (Stop)"| InsertX["Insert 'X' (ID 4a) before 'B'"] InsertX --> NextOp["Incoming op: Insert 'Y' (ID 5a) after ID 4a"] NextOp --> InsertY["Insert 'Y' directly after 'X' (No skip: 5a > 2a)"] end ```
Kleppmann highlights that while the rule is concise, proving that it never violates consistency requires rigorous validation. Inserting the subsequent character `Y` with ID `5a` (instructed to follow ID `4a`) is straightforward because `4a` is already positioned; `Y` sits directly after `X`. To clarify the symmetry, Kleppmann notes that `5a` will not skip over `2a` because `2a` is smaller, and on the peer side, inserting `P` (`4b`) would never skip over `4a` because `4b` is greater. Reflecting on why formal proofs were necessary for this logic, Martin Kleppmann emphasizes: “This rule it does actually work it takes a little bit of convincing and this is why we did all of that formal proof stuff because it's not entirely obvious immediately that this actually does the right thing but it turns out that it does actually always do the right thing.”
- **Comparison rule:** An incoming node skips over consecutive elements whose IDs are strictly greater than its own. - **Stop condition:** Skipping stops as soon as an element with a smaller ID (or the target end position) is reached. - **Determinism:** Symmetric checks guarantee that replicas process interleaved concurrent operations into identical final sequences regardless of network arrival order.
[42:25](https://www.youtube.com/watch?v=B5NULPSiOGw&t=2545s) Automerge, P2P Networking with Hypercore, and Research Resources
Kleppmann concludes by presenting the tooling and research literature underlying these concepts, primarily the open-source library Automerge. He encourages the audience to experiment with the code and build prototype applications, while remaining candid about its production readiness. Automerge is freely available under a permissive open-source license, but Kleppmann notes it originated as research software rather than a turnkey production package. Despite that caveat, it has already proven stable enough to support non-trivial peer-to-peer applications. He acknowledges the Dat project's Hypercore protocol, which provided the peer-to-peer append-only log networking foundation for their latest collaborative experiments.
Turning to academic references, Kleppmann points attendees to the published papers detailing the formal verification of CRDTs and their earlier work specifying a JSON CRDT. He caveats that the list-editing algorithm currently implemented inside Automerge has evolved beyond the algorithm documented in the earlier JSON CRDT paper; while an updated paper is still pending, an internal design document is maintained in Markdown format directly in the Automerge GitHub repository. Finally, he references his book (*Designing Data-Intensive Applications*), noting with a smile that while it does not focus on CRDTs, distributed systems engineers will find its material valuable. Regarding the maturity and potential of Automerge, Martin Kleppmann observes: “I'll tell you this is research code it's not production ready we're not pretending that it's perfect in all circumstances but it does seem to be working reasonably well we were able to build some non-trivial applications on top of it so maybe you will be able to as well.”
- **Library availability:** Automerge is open source, liberally licensed, and available for prototyping collaborative applications. - **Networking stack:** Networking in their recent experimental setup relies on Hypercore from the Dat project. - **Documentation and internals:** An architectural Markdown guide in the Automerge repository explains the current algorithm, which differs slightly from the earlier JSON CRDT publication. - **Recommended reading:** Formal verification research papers and Martin Kleppmann’s book on data-intensive systems.
## Mentioned Martin Kleppmann, Designing Data-Intensive Applications, University of Cambridge, QCon, Google Docs, Heidi Howard, Git, GitHub, Operational Transformation, Conflict-free Replicated Data Types, Atom, Riak, Isabelle, Automerge, JavaScript, Trellis, Trello, WebRTC, Pixel Pusher, Xavier Balan, MPL, Dat project, Hypercore, Hypermerge, WebSockets, Immutable.js
## Video description Download the slides & audio at InfoQ: https://bit.ly/2P1IGJe
Martin Kleppmann explores how to ensure data consistency in distributed systems, especially in systems that don't have an authoritative leader. He explains how to sync data between a phone and a laptop without sending it via a remote server. He also explores algorithms that allow several people to collaborate on a shared document, communicating via a peer-to-peer network.
This presentation was recorded at QCon London 2018: https://bit.ly/2hxsoN1
#SoftwareArchitecture #DistributedSystems #CRDT #Consistency #InfoQ #QCon #QConLondon
[Source](https://www.youtube.com/watch?v=B5NULPSiOGw)