Last modified: March 23, 2026

This article is written in: πŸ‡ΊπŸ‡Έ

Concurrent Writes

Concurrent writes happen when two or more clients write to the same key in a database at the same time, each unaware of the other's write. In replicated systems, these writes may arrive at different replicas in different orders, causing the replicas to diverge and hold conflicting values. Without a strategy to detect and resolve these conflicts, the system risks permanent inconsistency across its nodes.

Client A writes X=1              Client B writes X=2
  at time T                        at time T
        |                                |
        v                                v
  +------------+                   +------------+
  |  Replica 1 |                   |  Replica 2 |
  |   X = 1    |                   |   X = 2    |
  +------+-----+                   +------+-----+
         |                                |
         |      (replication lag)         |
         v                                v
  +------------+                   +------------+
  |  Replica 1 |                   |  Replica 2 |
  |  X = 1? 2? |                   |  X = 2? 1? |
  +------------+                   +------------+

  Both replicas received both writes but in
  different orders β€” which value is correct?

Detecting Concurrent Writes

Timeline at Node 1                Timeline at Node 2

  t1: Receive Write A               t1: Receive Write B
      (X = "apple")                     (X = "banana")
        |                                 |
  t2: Receive Write B               t2: Receive Write A
      (X = "banana")                     (X = "apple")
        |                                 |
        v                                 v
  Final state: X = "banana"         Final state: X = "apple"
                 ↑                                  ↑
                 |                                  |
              INCONSISTENT β€” replicas disagree!

Last Write Wins

Client A: SET X = "apple"  (timestamp: 100)
  Client B: SET X = "banana" (timestamp: 105)

  +---------------------+          +---------------------+
  |     Replica 1       |          |     Replica 2       |
  |                     |          |                     |
  |  Receives:          |          |  Receives:          |
  |   A (ts=100) first  |          |   B (ts=105) first  |
  |   B (ts=105) second |          |   A (ts=100) second |
  |                     |          |                     |
  |  Keeps: B (ts=105)  |          |  Keeps: B (ts=105)  |
  |  X = "banana"  βœ”    |          |  X = "banana"  βœ”    |
  +---------------------+          +---------------------+

  Both replicas converge on the same value,
  but Client A's write is lost forever.

Immutable Keys

Version Numbers

Server (key: "cart")                Client A                  Client B
  ========================            ========                  ========

  v1: cart = {milk}
        |
        +--- read ----------------------> gets v1, {milk}
        |
        +--- read ----------------------------------------------------> gets v1, {milk}
        |
        +<-- write(v1, {milk, eggs}) ---- Client A adds eggs
        |
  v2: cart = {milk, eggs}
        |
        +<-- write(v1, {milk, bread}) --------------------------------- Client B adds bread
        |                                                                (based on stale v1!)
  v3: cart = [{milk, eggs},
              {milk, bread}]          <-- server keeps BOTH as siblings
        |
        +--- read ----------------------> gets v3, [{milk, eggs}, {milk, bread}]
        |
        +<-- write(v3, {milk, eggs, bread})  Client A merges siblings
        |
  v4: cart = {milk, eggs, bread}      <-- conflict resolved, no data lost

Version Vectors

Replica A                    Replica B                    Replica C
  =========                    =========                    =========

  Write X = 1
  VA = {A:1}
       |
       +--- replicate -------> VB = {A:1}
       |                            |
       |                       Write X = 2
       |                       VB = {A:1, B:1}
       |                            |
       |                            +--- replicate -------> VC = {A:1, B:1}
       |                                                         |
  Write X = 3                                               Write X = 4
  VA = {A:2}                                                VC = {A:1, B:1, C:1}
       |                                                         |
       +--- compare with C's vector --------------------------->|
       |                                                         |
  {A:2} vs {A:1, B:1, C:1}                                      |
  Neither dominates the other β†’ writes are CONCURRENT            |
  System keeps both values as siblings                           |

Conflict Resolution Strategies Compared

Aspect Last Write Wins Immutable Keys Version Numbers Version Vectors
Data loss Yes β€” silent overwrites None None (siblings kept) None (siblings kept)
Complexity Very low Low Moderate High
Clock dependency Yes β€” needs timestamps No No No
Multi-replica support Yes Yes Single replica only Yes β€” designed for it
Merge responsibility System (automatic) Application (at read) Application (at read) Application (at read)
Best suited for Write-once data, caches Event logs, audit trails Single-leader with conflicts Multi-leader / leaderless
Real-world usage Cassandra, DynamoDB Event sourcing systems Single-node key stores Riak, Dynamo-style DBs