All questions

LWW Register / Map CRDT

Premium

LWW Register / Map CRDT

A last-write-wins (LWW) map is a conflict-free replicated data type (CRDT) where each key holds the value from the write with the highest timestamp, and equal timestamps are broken by the writer's node id so every replica independently agrees on the same winner. It lets many machines edit the same map while disconnected and later merge their states in any order, always converging on one result. Resolving conflicts by last-write-wins timestamp is exactly how Cassandra settles competing column writes and how Riak's LWW registers converge.

Build a factory lwwRegisterMapCrdt(nodeId) that returns a map whose writes carry a timestamp and whose replicas merge deterministically. Each key stores one stamped entry, { value, ts, node, deleted }, and a write replaces the current entry only when its (ts, node) pair is greater.

Signature

function lwwRegisterMapCrdt(nodeId: string): {
  set(key: string, value: unknown, timestamp: number): void;
  get(key: string): unknown | undefined;
  has(key: string): boolean;
  delete(key: string, timestamp: number): void; // stores a tombstone
  merge(other): void;                            // fold another replica's state in
  entries(): Array<[string, unknown]>;           // live keys only
};

Examples

const a = lwwRegisterMapCrdt('a');
a.set('color', 'red', 1);
a.set('color', 'blue', 2); // higher timestamp wins
a.get('color'); // 'blue'
a.delete('color', 3); // tombstone at ts 3 beats the ts 2 write
a.has('color'); // false
// Two replicas write 'color' at the SAME timestamp, then merge.
const a = lwwRegisterMapCrdt('node-a');
const b = lwwRegisterMapCrdt('node-b');
a.set('color', 'red', 5);
b.set('color', 'green', 5);

a.merge(b); // tie on ts 5: 'node-b' > 'node-a', so green wins
a.get('color'); // 'green'  (b.merge(a) gives the same answer)

Notes

  • Stamped entries — every key stores { value, ts, node, deleted }; set and delete stamp the entry with the given timestamp and this replica's nodeId.
  • Greater (ts, node) wins — a write replaces the current entry only when its timestamp is larger, or the timestamps are equal and its nodeId is larger by string comparison. An equal (ts, node) pair never overwrites.
  • Delete is a tombstonedelete stores a deleted: true entry that wins or loses by the same rule, so a later delete removes a key and a later set resurrects it. get, has, and entries hide tombstoned keys.
  • Merge is order-independentmerge keeps the greater (ts, node) per key, which makes it commutative, associative, and idempotent: replicas converge no matter the order writes and merges arrive in.
  • Do not worry about — clock skew, generating the timestamps, network transport, or garbage-collecting old tombstones; assume each node hands you a timestamp that only increases.

FAQ

What makes this a CRDT?
Its merge keeps the entry with the greater (ts, node) for each key, which makes merge commutative, associative, and idempotent. Replicas that have seen the same writes converge to the same map no matter what order those writes and merges arrive in.
Why break ties with the node id instead of picking either write?
Picking 'either' lets two replicas choose differently, so they never converge. Comparing node ids gives a total order that every replica computes identically, so an equal-timestamp tie has one deterministic winner everywhere.
What is the downside of last-write-wins?
The losing write is silently dropped; the two values are never combined. LWW is right for single-value fields like a setting or a name, but for text or sets you want a richer CRDT such as an RGA sequence or an OR-Set that preserves concurrent edits.

Unlock the solution & editor

  • Runnable editor + tests

    Solve in the browser with instant Jest feedback.

  • Detailed solutions

    Walkthroughs, edge cases, and complexity notes.

  • Multi-framework variants

    React, Vue, Vanilla, Angular — same question, different stacks.

Upgrade to Premium