Swytch vs Redis (Enterprise)
Redis Enterprise and Swytch both offer multi-region active-active replication. That’s the shared ground. The question this page is about is what “active-active” actually means in each product, because the answer is not the same.
Redis Enterprise achieves active-active through CRDTs. CRDTs are a beautiful piece of theoretical work, and for the right data types they give you genuine convergence guarantees. But Redis’s implementation has specific consequences that matter if you’re running queues, streams, counters, or any destructive operation across regions. Lists can deliver the same element twice on concurrent pops. Streams can skip entries on reads, re-deliver acknowledged ones under traffic redirection, and produce out-of-order IDs across consecutive read commands. All of this is documented by Redis directly. The section below walks through the specifics.
Swytch’s active-active uses envelope-commit over a causal DAG. When two instances issue concurrent RPOP calls on the
same list, the DAG serializes them so each consumes a distinct position. Both workers get an element; neither gets a
duplicate; the list shrinks by two. Same commands, different outcome from Redis Enterprise: exactly-once delivery
instead of at-least-once.
For cost comparisons, see Economics of Swytch.
| Redis Enterprise | Swytch | |
|---|---|---|
| Deployment | Dedicated cluster, managed or self-hosted | Sidecar or standalone binary, one or many nodes |
| Nodes | Primary-replica per region, synced via CRDT | One or more per region, active-active |
| Writers | Every region (via Active-Active / CRDB) | Every node, concurrently |
| Network needed? | Yes, between regions and clients | Yes, between nodes; app-to-node is local |
| Wire protocol | RESPv2 / RESPv3 | RESPv2 / RESPv3 |
| Command set | Redis commands + Enterprise modules | Redis commands, 100% compatible |
| Replication | Asynchronous CRDT merge between regions | Synchronous to interested nodes |
| Concurrent list pops | At-least-once (per Redis’s list docs) | Exactly-once via envelope-commit |
| Stream semantics | XREAD may skip entries; XREADGROUP at-least-once across regions (per Redis’s streams docs) | Single-node Redis semantics across any number of regions |
| Partition handling | Per-region writes continue, CRDT merges on heal | Both sides continue; non-transactional writes merge on heal |
| Durability | Disk (RDB + AOF), replication | In-memory across subscribed nodes by default; disk via Swytch Cloud |
| Modules | RediSearch, RedisJSON, RedisGraph, RedisTimeSeries, etc. | Not supported |
| Operational surface | Managed service or dedicated ops team | One binary, DNS-based membership |
| License | Commercial, per-region | AGPL (open source) + commercial |
The question every multi-region deployment has to answer is what happens when two regions write to the same thing at the same time.
Redis Enterprise’s answer is CRDTs. For commutative operations (counters, sets), CRDTs work well; the merge is mathematically guaranteed to produce the same result on every region. For non-commutative operations, Redis has designed specific CRDT behaviors per data type, and for some of those data types, the behavior has correctness implications.
The most significant is lists. Redis Enterprise’s Active-Active lists documentation states, verbatim: “Lists in Active-Active databases guarantee that each element is POP-ed at least once, but cannot guarantee that each element is POP-ed only once.” The documentation goes on to explain: “Two parallel RPOP operations performed by two different Active-Active database instances can get the same element in the case of a concurrent operation.”
The recommended mitigation, per Redis: route all pops to a single Active-Active instance.
That recommendation is the mitigation, but it also erases the reason you bought Active-Active. If every destructive operation has to funnel through one instance, you have one instance of availability for that workload, in one region, with the other regions’ Active-Active nodes along for the ride. It’s a workaround, not a solution.
Streams are worse, because streams are specifically the primitive Redis users reach for when they need reliable event processing. The Active-Active streams documentation names several failure modes:
XREADmay skip entries when a stream is written from more than one region. Redis’s recommendation: “For reliable stream iteration, use XREADGROUP instead.”XREADGROUPacross regions “can result in regions reading the same entries”, because “Active-Active Streams is designed for at-least-once reads or a single consumer.”- Under traffic redirection to a different region,
XREADGROUPcan return entries that have already been read and even entries that have already been acknowledged. - Sequential
XREADGROUPcalls can reply with decreasing IDs, because ordering isn’t guaranteed across commands. - Unless you restrict XADD to strict ID generation mode (which rejects full IDs with both a millisecond and sequence part), duplicate stream entry IDs are possible.
None of these are obscure edge cases. They’re the published behavior of the primitive a lot of Redis users specifically chose because they needed reliability. “Designed for at-least-once reads” is a quoted claim from Redis’s own documentation, not a framing Swytch is putting on it.
The same issue shapes other patterns. Concurrent transactions (MULTI/EXEC across Active-Active instances) rely on
the same CRDT machinery and have the same fundamental constraint: the merge function determines the outcome, and for
some merge functions the outcome isn’t what a serializable semantics would give you.
Swytch’s active-active is serializable. Concurrent operations get ordered before they commit, and the outcome of any set of operations is consistent with some serial execution of them; not a merge of concurrent ones.
The consequence, for streams specifically: using Swytch in a single region or across fifty is semantically equivalent to
using single-node Redis. XREAD doesn’t skip entries. XREADGROUP doesn’t re-deliver acknowledged ones. Consecutive
reads return IDs in the expected order. None of this requires stream-specific implementation cleverness; it falls out of
the fact that the whole database is serializable. What changes as you add regions is speed, bounded by physics; a write
committed in Sydney has to reach a subscriber in Frankfurt before Frankfurt sees it, and that takes the cross-region
RTT. The semantics don’t change. The latency does.
This is not a marginal improvement. For any stateful workload (queues, counters, leaderboards, rate limiters, inventory, anything where duplicate processing has a cost) it’s the difference between “works correctly” and “works until it doesn’t, and when it doesn’t you find out in an incident.”
Reach for Redis Enterprise when:
- You need Redis modules (RediSearch, RedisJSON, RedisGraph, etc.) that aren’t in OSS.
- Your workload is primarily key-value caching where CRDTs are well-behaved (non-destructive operations, commutative updates).
- You’ve already invested in Redis Enterprise tooling and the team knows the operational model.
Reach for Swytch when:
- You’re running queues, counters, or any destructive operation across regions and need exactly-once semantics.
- You want real transactional isolation in multi-region deployments, not CRDT merge semantics.
- You want simpler ops. No separate cluster tier, no per-region license, just add servers.
- You want to cut infrastructure and licensing costs. See Economics of Swytch for the math.
Redis Enterprise and Swytch both solve multi-region active-active, and they solve it differently. Redis Enterprise uses CRDTs, which for the right data types work beautifully but for destructive operations like list pops can deliver the same element to two different regions concurrently (a limitation Redis’s own documentation is explicit about). The recommended workaround (route pops through one instance) is not Active-Active in any meaningful sense. Swytch uses envelope-commit over a causal DAG, which gives you exactly-once semantics across regions for destructive operations, transactions, and anything else where correctness under concurrency matters. If your workload fits in the CRDT sweet spot and you’re already invested in Enterprise tooling, Enterprise is a reasonable choice. If your workload includes the kinds of operations CRDTs don’t handle cleanly, and most real application workloads do, Swytch is what active-active looks like when it’s built for correctness first.