Distributed Systems for Backend Engineers · Data Distribution and Agreement

Conflict Resolution and CRDTs

Merge concurrent updates in multi-leader and offline systems.

When multiple replicas accept writes (multi-region, offline-first apps, collaborative editing), concurrent updates conflict. Strategies: last-write-wins (simple, loses data), application merge (custom logic or user resolution), and CRDTs — data types that merge deterministically without coordination (G-Counter, PN-Counter, OR-Set, LWW-Register, sequence CRDTs for text). Libraries: Automerge, Yjs; databases: Riak, Redis Enterprise CRDBs, Azure Cosmos DB conflict policies.

Conflict strategies

Strategy Data loss? Complexity Use for
Last-write-wins Yes (concurrent writes) Low Caches, idempotent overwrites
Custom merge / user resolves No (if done right) Medium–high Documents, records
CRDT counters/sets No Medium Likes, carts, flags
Sequence CRDTs (Yjs/Automerge) No Library-provided Collaborative text, offline apps
class GCounter:
    def __init__(self, node_id: str):
        self.node_id, self.counts = node_id, {}

    def increment(self, n: int = 1):
        self.counts[self.node_id] = self.counts.get(self.node_id, 0) + n

    def value(self) -> int:
        return sum(self.counts.values())

    def merge(self, other: "GCounter"):
        for node, c in other.counts.items():          # element-wise max: commutative, idempotent
            self.counts[node] = max(self.counts.get(node, 0), c)

Common pitfalls

  • LWW on wall clocks for important data.
  • Ignoring conflicts in offline-first apps.
  • Rolling your own CRDTs for text editing.

Key points

  • Concurrent writes need a merge strategy
  • CRDTs merge without coordination
  • Use Yjs/Automerge for collaboration

Further reading: crdt.tech

Practice questions

What properties make CRDT merges safe in any order?

Answer

Merge is commutative, associative and idempotent, so replicas converge regardless of delivery order or duplication.

Why is last-write-wins risky for user data?

Answer

Concurrent updates are resolved by timestamp (with clock skew), silently discarding one user's changes.

Open in the app to mark lessons complete, take notes and track your progress.