Redis Active-Active CRDTs resolve write conflicts by using a Conflict-free Replicated Data Type (CRDT) that inherently guarantees eventual consistency without requiring a central coordinator to resolve differing states.

Let’s see it in action. Imagine two Redis nodes, redis-01 and redis-02, both hosting the same LWW-SET (Last-Write-Wins Set) data structure. We’re going to add the same element, user:123, to both nodes, but with slightly different timestamps.

On redis-01:

redis-cli -h redis-01.example.com -p 6379 XADD my_set * user:123 timestamp:1678886400000

And on redis-02:

redis-cli -h redis-02.example.com -p 6379 XADD my_set * user:123 timestamp:1678886401000

Now, let’s check the contents of my_set on both nodes.

On redis-01:

redis-cli -h redis-01.example.com -p 6379 XRANGE my_set - + COUNT 10

Output might look like:

1) 1) "1678886400000-0"
   2) 1) "user:123"
      2) "timestamp:1678886400000"

On redis-02:

redis-cli -h redis-02.example.com -p 6379 XRANGE my_set - + COUNT 10

Output might look like:

1) 1) "1678886401000-0"
   2) 1) "user:123"
      2) "timestamp:1678886401000"

Notice that each node thinks it has the authoritative version of user:123 based on its local timestamp. This is where CRDTs shine. Because these are LWW-SET entries, when the replication mechanism syncs, the CRDT logic on the receiving node will compare the timestamps of the incoming entry with any existing entry for user:123. The entry with the higher timestamp will "win" and overwrite the older one. If replication is configured correctly (e.g., using Redis Streams for change propagation and CRDT commands for state updates), both nodes will eventually converge to the state reflecting the write with the latest timestamp.

The problem CRDTs solve is maintaining data consistency across multiple replicas that can accept writes independently. Traditional master-replica setups often require writes to go through a single master, or use complex consensus protocols (like Raft or Paxos) for distributed writes, which can introduce latency or single points of failure. Active-Active CRDTs, however, allow any replica to accept writes, and the CRDT data structure itself provides a mathematical guarantee that all replicas will eventually agree on the same state, even if writes arrive in different orders or concurrently.

Internally, Redis uses specialized data structures and commands for CRDTs. For sets, LWW-SET (Last-Write-Wins Set) is common. When you add an element, you associate it with a timestamp. The CRDT logic ensures that if the same element is added on different replicas with different timestamps, the replica that receives the write with the later timestamp will prevail. This is achieved through careful management of metadata associated with each element. For LWW-SET, this metadata is primarily the timestamp. When a replica receives an update, it compares the timestamp of the incoming update with the timestamp of the existing data. If the incoming timestamp is greater, it replaces the existing data. If it’s less, it’s discarded. If they are equal, the behavior might depend on the specific CRDT implementation (e.g., using a unique ID to break ties).

The exact levers you control are the CRDT data types themselves and how you populate them. For example, using CC-SET (Commutative-Closure Set) for sets allows for concurrent additions and removals without conflict, as the operations commute. For counters, GC-Counter (Grow-Only Counter) allows concurrent increments, and the final value is the sum of all increments across all replicas. The key is understanding the properties of each CRDT type and choosing the one that best fits your application’s consistency and conflict resolution needs.

The mechanism for propagating these changes is typically built on top of Redis Streams. A write to a CRDT data type on one node generates a record in a Redis Stream. Other replicas consume this stream, and upon receiving a record, they apply the CRDT operation to their local data structure. This stream-based approach ensures that all changes are durably logged and can be replayed, facilitating eventual consistency.

What most people don’t realize is that the "conflict resolution" isn’t a separate, active process that Redis runs after a conflict is detected. Instead, the CRDT data type is the conflict resolution mechanism. The structure of the data type, combined with its associated metadata (like timestamps for LWW), dictates how concurrent writes are reconciled as they are applied. There’s no post-hoc reconciliation phase; the data structure inherently handles it through its defined mathematical properties.

The next conceptual hurdle is understanding how to handle more complex data structures like maps or lists, and the implications of different CRDT types for application logic.

Want structured learning?

Take the full Redis course →