Command Support

Which Redis commands are replicated across datacenters, which execute locally and never leave the datacenter, and which are refused with an error.

The command rules follow the module generation, not the replication mode

On Redis 7.2 the same replication module serves both Disaster Recovery (peerof) and Active-Active (mesh), and it classifies every command identically in both modes. What the mode changes is which members accept application writes, and therefore how often the conflict-resolution behavior below is actually exercised.

Redis 6.0 runs the legacy module, which supports Disaster Recovery only, replicates a smaller command set, and applies none of the guards. See Redis 6.0 — the legacy module.

Summary by mode

Disaster Recovery (peerof)Active-Active (mesh)
Redis versions6.0, 7.27.2
Refused with an error (Redis 7.2)MOVE, SWAPDB, RESTORE always; FLUSHALL/FLUSHDB while any peer is attachedIdentical
Executed locally, never replicatedIdentical on Redis 7.2 — see Executed locally, never replicatedIdentical
Replicated write commandsIdentical on Redis 7.2; a smaller set on Redis 6.0Identical to Redis 7.2 Disaster Recovery
Conflict resolution in practiceRarely exercised — only the upstream takes application writes, so concurrent conflicting writes do not normally ariseExercised continuously — every member takes writes, so every rule in Replicated write commands is live
Both modes enforce the same refusals

The refusals are enforced by the module's command filter, which is installed whenever cross-datacenter replication is enabled on Redis 7.2. A MOVE, SWAPDB, or RESTORE therefore fails on a Disaster Recovery instance exactly as it does on an Active-Active member, even though a Disaster Recovery instance has a single writer. Applications that rely on these commands must be changed before the instance joins a replication group.

Refused with an error

These commands do not execute at all on Redis 7.2. The client receives an error and nothing is written locally or replicated.

CommandWhen it is refusedWhy
MOVE, SWAPDBAlways, once replication is enabledMoving a key between logical databases, or swapping two whole databases, has no per-key ordering that peers can reproduce. Concurrent writes would interleave differently on each member and the datasets would diverge permanently, with nothing to repair them.
RESTORE (key-level)Always, once replication is enabledA serialized value carries its own embedded write timestamp. Replicating it would put that timestamp in conflict with the timestamp of the frame that carries it, letting a stale payload win against newer data on peers; executing it locally only would silently diverge the member that ran it. RESTORE-ASKING is a different command, used internally by Redis Cluster resharding, and is not refused.
FLUSHALL, FLUSHDBWhile the instance has any peer attached — an upstream configured, or a downstream connectedA flush is local-only and is never replicated. Running one inside a live replication group would diverge that member from the rest, and would discard the tombstones it keeps for previously deleted keys, so a delayed write from a peer could later resurrect a key that everyone else had deleted.

The errors are, respectively:

ERR move is not supported in active-active — its effect cannot converge across peers; Redis Enterprise refuses it the same way
ERR flushall is refused while this node has peers attached (1 upstream, 0 downstream) — FLUSH is local-only and must not run inside a live active-active mesh; detach all peers first, then flush the isolated node

To empty a replication group, remove the connections (or the ActiveRedisMesh resources), flush each isolated instance, then re-create them. Alternatively, recreate the instances.

FUNCTION RESTORE is not in this list — it is supported. Only the key-level RESTORE is refused.

Executed locally, never replicated

These commands run exactly as they do on unmodified Redis. There is no error and no rejection — they simply produce no cross-datacenter effect, so each datacenter's state for them is independent.

Command(s)Notes
All stream commands — XADD, XDEL, XTRIM, XSETID, and every consumer-group operation (XGROUP, XREADGROUP, XACK, XCLAIM, XAUTOCLAIM)Each datacenter's streams are self-contained. Consumer groups work fully within a datacenter but do not converge across datacenters, because pending-entry and consumer-ownership state is node-local. Use a message-queue component if you need cross-datacenter delivery.
PUBLISH, SPUBLISH, and the SUBSCRIBE familyPub/sub is ephemeral and per-connection. Use a message-queue component if cross-datacenter delivery is required.
MIGRATE, RESTORE-ASKINGThe Redis Cluster resharding pair. Resharding is a per-datacenter topology operation; replicating it would permanently lose the migrated key in every peer datacenter.
WAIT, WAITAOF, CONFIG, DEBUG, CLIENT, ACL, and server-administration commandsNot write commands.
MULTI, EXEC, DISCARD, WATCHThe transaction boundary is not preserved. Each command inside the transaction is replicated individually — see No cross-datacenter atomicity.
Key-lifecycle commands are isolated for stream keys

Because a peer's same-named key is an unrelated local stream, generic key commands are prevented from crossing datacenters when they touch a stream key:

  • Setting a TTL on a stream key is refused — a replicated expiry would delete a peer's unrelated local stream.
  • PERSIST on a stream key executes locally but does not replicate.
  • DEL, RENAME, and COPY involving a stream key are not replicated.

Replicated write commands

Everything listed here is replicated to every other member of the replication group. The Conflict behavior column describes how two members that wrote the same key at the same time are reconciled. In Disaster Recovery mode only the upstream takes application writes, so these rules apply but are rarely exercised; in Active-Active mode they are exercised continuously.

Five conflict rules are used throughout:

RuleBehavior
Last-write-winsThe write with the higher timestamp wins; ties are broken by the higher serviceID. Hashes and sorted sets apply it per field and per member rather than to the whole key. This rule depends on synchronized clocks — see Clock synchronization.
Additive counter (PN-Counter)Each member's contribution is tracked separately and the value is the sum across all members, so concurrent increments from different datacenters all count.
Add-wins set (observed-remove set)A removal only cancels the additions it has already seen, so an addition made concurrently on another member survives the removal.
Element-level listEvery list element has its own identity, so concurrent list changes in different datacenters converge to one consistent list. The resulting order is deterministic but is not necessarily insertion order.
TTL registerA key's expiry is resolved separately from its value: a causally later change wins even when it shortens the TTL, and two genuinely concurrent changes resolve to the longer deadline. PERSIST asserts an infinite deadline and therefore beats any concurrent finite TTL.

Strings

CommandConflict behaviorNotes
SETLast-write-winsA conditional SET (NX/XX) is evaluated on the writing member; peers receive an unconditional SET when it performed, and nothing when it did not.
SETNXLast-write-winsReplicated as an unconditional SET when it set the key.
SETEX, PSETEXLast-write-winsThe relative TTL is converted to an absolute deadline before replication, so peers do not recompute it against their own clock.
SETRANGE, APPEND, GETSETLast-write-winsReplicated as the resulting absolute value, not as the modification.
GETDELLast-write-winsThe read is local; the deletion replicates.
GETEXLast-write-winsOnly the TTL change replicates.
INCR, DECR, INCRBY, DECRBYAdditive counterConcurrent increments in different datacenters are summed rather than overwriting one another. The key's TTL is preserved.
INCRBYFLOATAdditive counterMerged at full floating-point precision.
MSET, MSETNXLast-write-wins per keySplit into independent per-key writes — replicated, but not atomic across datacenters.
COPYLast-write-winsReplicated as a rebuild of the destination key.

Hashes

CommandConflict behaviorNotes
HSET, HMSETLast-write-wins per fieldTwo datacenters writing different fields of the same hash both keep their writes.
HSETNXLast-write-wins per fieldReplicated as HSET when it set the field.
HDELAdd-wins setA field written concurrently on another member survives the deletion.
HINCRBY, HINCRBYFLOATAdditive counter per fieldConcurrent increments of the same field are summed.

Sets

CommandConflict behaviorNotes
SADDAdd-wins set
SREMAdd-wins setA concurrent, not-yet-observed SADD of the same member survives.
SMOVEAdd-wins setSplit into a removal on the source and an addition on the destination.
SPOPLast-write-winsReplicated as a removal of the members actually popped. At-least-once across datacenters — see At-least-once pops.
SINTERSTORE, SUNIONSTORE, SDIFFSTORELast-write-wins on the destinationThe result is computed locally and the destination key is rebuilt on peers.

Sorted sets

CommandConflict behaviorNotes
ZADDLast-write-wins per memberA flagged ZADD (NX/XX/GT/LT/INCR) is evaluated locally, and only the members whose score actually changed are replicated, with their exact resulting scores.
ZINCRBYAdditive counterApplied on peers as a relative increment, preserving any base score set by ZADD.
ZREMAdd-wins set
ZREMRANGEBYSCORE, ZREMRANGEBYRANK, ZREMRANGEBYLEXLast-write-wins
ZPOPMIN, ZPOPMAX, BZPOPMIN, BZPOPMAX, ZMPOP, BZMPOPLast-write-winsReplicated as a removal of the members actually popped. At-least-once across datacenters. Blocking variants run non-blocking on the receiving member.
ZUNIONSTORE, ZINTERSTORE, ZDIFFSTORE, ZRANGESTORELast-write-wins on the destinationThe destination key is rebuilt on peers.

Lists

CommandConflict behaviorNotes
LPUSH, RPUSH, LPUSHX, RPUSHXElement-level list
LINSERTElement-level list
LSETElement-level listLast-write-wins on the value of that one element.
LTRIM, LREMElement-level list
LPOP, RPOP, BLPOP, BRPOP, LMPOP, BLMPOPElement-level listAt-least-once across datacenters. Blocking variants run non-blocking on the receiving member.
RPOPLPUSH, BRPOPLPUSH, LMOVE, BLMOVEElement-level listReplicated as a removal on the source plus an insertion on the destination.
Do not use a list as an exactly-once queue across datacenters

Pops are at-least-once: the same element can be popped in two datacenters before they synchronize. Consume from a single datacenter, or make consumers idempotent.

Keyspace

CommandConflict behaviorNotes
DEL, UNLINKLast-write-winsA concurrent write with a newer timestamp beats the deletion. UNLINK runs synchronously rather than in the background.
EXPIRE, EXPIREAT, PEXPIRE, PEXPIREATTTL registerConverted to an absolute deadline before replication. A causally later change wins even if it shortens the TTL; two concurrent changes resolve to the longer deadline. NX/XX/GT/LT are evaluated on the writing member, and an unmet condition replicates nothing.
PERSISTTTL registerBeats any concurrent finite TTL; a causally later PEXPIREAT still re-expires the key.
RENAME, RENAMENXLast-write-wins on the destinationReplicated as a rebuild of the destination key plus a deletion of the source, so that the destination's own conflict resolution stays correct.
SORT ... STORELast-write-wins on the destinationSORT without STORE is a read and is not replicated.

Bitmaps, HyperLogLog, and geospatial

CommandConflict behaviorNotes
SETBITLast-write-winsReplicated as the resulting absolute value, so a concurrent bit set on another member can be lost.
BITFIELDLast-write-winsReplicated as the resulting absolute value. INCRBY subcommands are not treated as additive counters. BITFIELD_RO is a read.
BITOPLast-write-wins on the destination
PFADDCommutativeHyperLogLog registers only grow, so concurrent additions converge.
PFMERGECommutativeThe result is unioned into the destination on peers, so concurrent PFADD and PFMERGE converge to the true union.
GEOADDLast-write-wins per memberA conditional GEOADD (NX/XX/CH) replicates only the members that actually changed.
GEORADIUS ... STORE, GEORADIUSBYMEMBER ... STORE, GEOSEARCHSTORELast-write-wins on the destinationWithout STORE these are reads and are not replicated.

Scripting and functions

CommandConflict behaviorNotes
EVAL, EVALSHA, FCALLPer command inside the scriptThe individual writes the script performs are replicated, not the script call itself. Each write follows the rule for its own command. EVAL_RO, EVALSHA_RO, and FCALL_RO write nothing.
SCRIPT LOAD, SCRIPT FLUSHLast-write-winsThe script registry is replicated so a script loaded in one datacenter becomes available in the others.
FUNCTION LOAD, FUNCTION DELETE, FUNCTION FLUSH, FUNCTION RESTORELast-write-wins per libraryThe function-library registry is replicated per library. FUNCTION LIST, FUNCTION DUMP, and FUNCTION STATS are local reads.
Scripts do not get transactional replication

Because each write a script performs is replicated on its own, a script is subject to the same per-command rules as any other client. A script that is not idempotent is not made idempotent by being a script.

Behavior that differs from standalone Redis

Design application logic around these. They are consequences of the replication model, not defects.

At-least-once pops

LPOP, RPOP, SPOP, ZPOPMIN, ZPOPMAX, and their blocking and multi-key variants are exactly-once on a single member but at-least-once across the replication group. Two members popping concurrently, before they synchronize, can each consume the same element. Consume from a single member, or make consumers idempotent.

No cross-datacenter atomicity

MULTI/EXEC, MSET, and MSETNX are replicated per key or per command. The keys all arrive and the members converge, but peers do not apply the group atomically — a peer can briefly observe part of a transaction.

Writes of different types to one key resolve silently

Concurrent writes of different types to the same key (SET key in one datacenter, HSET key in another) resolve by timestamp, with ties broken by the higher serviceID. The loser's data is discarded without a merge and without an error.

Deleted data occupies memory until every member has acknowledged it

Deletions are retained as tombstones — records that a key, field, or element was deleted — so that a delayed write from a peer cannot resurrect deleted data. A tombstone is released only after every active peer has acknowledged it and a minimum age of five minutes has passed. A peer that is unreachable for a long time therefore holds tombstones alive on every other member — decommission a datacenter that is gone for good, as described in Limitations and Risks. Large clock skew narrows this protection; see Clock synchronization.

The module's bookkeeping keys are visible

The module stores some replication bookkeeping as ordinary Redis keys under the reserved __arcr_ prefix. They are counted by DBSIZE and returned by SCAN and KEYS until they are collected, and they are derived independently on each member, so their number and timing legitimately differ between datacenters. Any tooling that compares datasets across datacenters must exclude the whole __arcr_ prefix. Applications must not write to it.

Redis 6.0 — the legacy module

Redis 6.0 runs the frozen legacy module and supports Disaster Recovery only. Its behavior differs from Redis 7.2 in two ways that matter operationally.

It replicates a smaller set of commands. The commands it replicates are:

GroupCommands
KeyspaceDEL, UNLINK, RENAME, RENAMENX, EXPIRE, EXPIREAT, PEXPIRE, PEXPIREAT, PERSIST
StringsSET, SETNX, SETEX, PSETEX, APPEND, SETRANGE, GETSET, MSET, MSETNX, INCR, DECR, INCRBY, DECRBY, INCRBYFLOAT
HashesHSET, HSETNX, HMSET, HDEL, HINCRBY, HINCRBYFLOAT
SetsSADD, SREM, SMOVE, SPOP, SINTERSTORE, SUNIONSTORE, SDIFFSTORE
Sorted setsZADD, ZINCRBY, ZREM, ZREMRANGEBYSCORE, ZREMRANGEBYRANK, ZREMRANGEBYLEX, ZUNIONSTORE, ZINTERSTORE, ZPOPMIN, ZPOPMAX, BZPOPMIN, BZPOPMAX
ListsLPUSH, RPUSH, LPUSHX, RPUSHX, LINSERT, LSET, LTRIM, LREM, LPOP, RPOP, BLPOP, BRPOP, RPOPLPUSH, BRPOPLPUSH, SORT ... STORE
BitmapsSETBIT, BITFIELD, BITOP
HyperLogLogPFADD, PFMERGE
GeospatialGEOADD, GEORADIUS ... STORE, GEORADIUSBYMEMBER ... STORE
ScriptingSCRIPT LOAD, SCRIPT FLUSH

Commands introduced after Redis 6.0, and the commands listed under Executed locally, never replicated, are not replicated by the legacy module — including all stream commands, pub/sub, MIGRATE, and the MULTI/EXEC boundary.

It has none of the guards. The legacy module does not refuse any command. FLUSHALL, FLUSHDB, MOVE, SWAPDB, and RESTORE are wrapped and replicated to the downstream instead of being rejected.

On Redis 6.0, a flush reaches the downstream

Because the legacy module replicates them, a FLUSHALL or FLUSHDB issued on a Redis 6.0 upstream also empties every downstream instance. There is no confirmation and no error. Treat both commands as destructive across the whole replication group on Redis 6.0, and consider restricting them with an ACL.

On Redis 7.2 the same commands are refused while peers are attached — see Refused with an error.

To move an existing Redis 6.0 group onto the new module, follow Upgrade a Disaster Recovery Group from Redis 6.0 to Redis 7.2.