
Data
Redis vs ElastiCache: What the Managed Version Decides for You
ElastiCache 7.1 is Redis OSS 7.0-compatible; newer versions run Valkey. What its defaults, blocked commands and failover decide, and what self-hosting returns.
A cache is the easiest managed service to adopt and the hardest to notice depending on. A team ticks a box, an endpoint appears, and three years later the application relies on an eviction policy nobody chose, a failover nobody has rehearsed and a version line that now carries a surcharge.
This article is the operator-level difference, every line sourced to AWS or upstream documentation, as of 4 November 2026. It does not crown a winner. The two options sit at different layers, and the deciding question is who is on call.
The comparison is mislabelled
"Redis" names an engine and a licence. "ElastiCache" names a hosting model. The useful questions are which engine the service runs, which settings it has already chosen, and which controls it has taken away.
ElastiCache's newest engines are Valkey, the Linux Foundation fork, and its Redis OSS line stops at an AWS label that does not exist upstream. So the real decision has three parts: engine, licence, and who owns the defaults.
The pattern is the same one this site has traced for streams in leaving Kinesis and for queues in leaving SQS: the managed product's semantics become the application's semantics, and you only find out which ones when you try to leave.
What ElastiCache actually runs in 2026
AWS's engine-versions page says serverless caches and node-based clusters "support all Redis OSS versions 7.1 and before" — and then that "ElastiCache v7.1 is compatible with Redis OSS v7.0." There is no Redis 7.1 upstream: the redis/redis tags go from 7.0.x straight to the 7.2 release candidates. ElastiCache version numbers are AWS labels, not upstream releases.
The same is true on the Valkey side. The page documents ElastiCache versions 7.2.6, 8.0, 8.1, 8.2, 9.0 and 9.1 for Valkey, and notes that "ElastiCache v8.2 is compatible with Valkey v8.1" — it adds vector search through the valkey-search module, but valkey-io/valkey has no 8.2 tag. Version 9.0 is where AWS introduced durability "via a Multi-AZ transactional log", which matters for failover below.
Now the licences. The Redis OSS 7.0 line that ElastiCache 7.1 tracks is, upstream, BSD-licensed: the redis/redis README states that 7.2.x and earlier are BSDv3. Starting with 7.4, Redis Inc. moved to a dual RSALv2/SSPLv1 licence and acknowledged that "Redis is no longer open source under the OSI definition". With Redis 8 it added AGPLv3 as a third option, so 8.0 and later are RSALv2/SSPLv1/AGPLv3 at the user's choice.
Valkey was announced by the Linux Foundation on 28 March 2024 as a continuation of Redis 7.2.4 under BSD 3-clause. At the time of writing the latest Valkey release is 9.1.3 and the latest stable Redis Open Source is 8.10.3. The supported-versions list on AWS's engine-versions page stops at the Redis OSS 7.1 label, and the page offers no Redis 8, so on that evidence, running the Redis 8 line means running it yourself.
AWS prices the fork to pull you towards it. At launch, Valkey on ElastiCache was priced 33% lower on serverless and 20% lower on node-based clusters than the other engines. The licence that matters for sovereignty, though, is the one you could run without AWS: Valkey's BSD-3, or Redis 8's AGPLv3.
The defaults the managed version chooses for you
Three defaults change application behaviour, and a long-lived ElastiCache application has likely absorbed all three without anyone writing them down.
Eviction: volatile-lru, not noeviction
On node-based clusters the parameter-group default for maxmemory-policy is volatile-lru: when memory fills, keys with a TTL are evicted by least-recently-used estimate. It is modifiable in a custom parameter group, with immediate effect. On serverless caches there are no parameter groups at all; the configuration is not modifiable and volatile-lru is fixed.
Upstream redis.conf defaults to noeviction, which does not evict anything and returns an error on writes once memory is full. Under volatile-lru, a full cache silently drops session or rate-limit keys that carry a TTL. Under noeviction, a full cache starts failing writes loudly. A team that moves from ElastiCache to a stock self-hosted config without carrying the policy across has changed its application's behaviour under memory pressure without changing a line of code.
Memory you are not allowed to use
`reserved-memory-percent` sets aside part of each node's memory for non-data use, defaults to 25%, and comes with the instruction "Do not reduce this value." For production on small instances AWS says to raise it to 30%, and on micro instances to 50%. The parameter is ElastiCache's own, not part of the Valkey or Redis OSS code — self-hosted, the equivalent is whatever headroom you leave between maxmemory and the host's RAM.
Parameters you cannot touch
Some parameters are not modifiable at all — cluster-enabled and replica-allow-chaining among them — and the default parameter group cannot be changed, so any tuning means creating a custom group. Cluster mode itself is a one-way door: AWS can move a cluster from cluster mode disabled to enabled online, via a "compatible" step, but not back once enabled, and the endpoints change when it does.
Before any migration, record the effective values rather than remembering them. This reads a node-based cluster's parameter group; it does not apply to serverless, whose configuration is fixed.
#!/usr/bin/env bash
set -euo pipefail
REGION="eu-west-1"
CLUSTER_ID="orders-cache-0001-001" # any node in the replication group
GROUP="$(aws elasticache describe-cache-clusters \
--region "$REGION" \
--cache-cluster-id "$CLUSTER_ID" \
--query 'CacheClusters[0].CacheParameterGroup.CacheParameterGroupName' \
--output text)"
# Every parameter, user-set and engine-default, with its source and modifiability.
aws elasticache describe-cache-parameters \
--region "$REGION" \
--cache-parameter-group-name "$GROUP" \
--output json > "params-${GROUP}.json"
# The two values that change application behaviour on migration.
jq -r '.Parameters[]
| select(.ParameterName == "maxmemory-policy" or .ParameterName == "reserved-memory-percent")
| "\(.ParameterName)=\(.ParameterValue) (source: \(.Source))"' "params-${GROUP}.json"Commands you do not get, and why it matters operationally
"To deliver a managed service experience", ElastiCache's restricted-command list, documented for caches running Redis OSS, removes the commands that require advanced privileges:
CONFIG— no runtime inspection or change of settings; everything goes through parameter groups.BGSAVE,SAVE,BGREWRITEAOF— persistence is AWS's backup feature, not yours.REPLICAOF/SLAVEOF,SYNC/PSYNC,MIGRATE— you cannot attach an outside replica or stream data out with native replication.CLUSTER FAILOVER,SHUTDOWN,DEBUG— failover and lifecycle belong to the control plane.ACL SETUSER,ACL DELUSER— users are managed through the ElastiCache API instead.
Serverless caches block more, including KEYS, MONITOR, SLOWLOG, LATENCY, CLIENT LIST, CLIENT KILL, WAIT, SWAPDB and LASTSAVE. Two of the serverless omissions are application features rather than admin tools: FUNCTION/FCALL, so server-side functions do not run, and CLIENT TRACKING, so client-side caching does not work.
The effect runs both ways. Runbooks written against ElastiCache never needed CONFIG GET or a BGSAVE before maintenance; self-hosted, those are the first commands on-call reaches for. And tooling that assumes the full surface fails for reasons of policy, not bugs: replication-based migration via REPLICAOF fails against any ElastiCache cache, and on serverless caches a MONITOR-driven debugger and client-side caching through CLIENT TRACKING fail too.
Failover you inherit versus failover you run
On a Multi-AZ failure, ElastiCache promotes "the replica with the least replication lag" and propagates its DNS name so the primary endpoint does not change. AWS says writes resume as soon as promotion completes, "typically just a few seconds". And because replication is asynchronous, AWS states that "a small amount of data might be lost due to replication lag".
Both of those statements describe durability disabled, which is what you get unless you ask otherwise: on Valkey 9.0, --durability default resolves to disabled. AWS documents that mapping for 9.0; it decides default "based on engine version and cluster configuration", so check it on later versions rather than assuming it.
With durability enabled, the picture changes. AWS says that with synchronous writes, failover means "zero data loss" because all committed data sits in a Multi-AZ transactional log, at the cost of write latency rising from microseconds to single-digit milliseconds. With asynchronous writes, up to 10 seconds of uncommitted data may be lost. The limitations are narrow:
- Valkey 9.0 or later, node-based, cluster mode enabled — no Serverless, and no cluster-mode-disabled clusters.
- Instance families R8g, R7g, R6g, M8g, M7g, M6g, C8gn or C7gn only; Multi-AZ with at least one replica per shard.
- No Global Datastores, Outposts, Local Zones or data tiering; at most 100 MiBps of writes per primary.
- Encryption at rest is required and enabled automatically; changing durability on an existing cluster requires TLS.
- No online migration from self-hosted Valkey or Redis OSS onto a durable cluster.
On ElastiCache for Redis OSS, Multi-AZ and append-only file persistence are mutually exclusive. A customer-initiated reboot of the primary does not trigger failover, and that does not make it the safe maintenance action: AWS says the rebooted primary "is cleared of data when it comes back online", and the read replicas, seeing the cleared primary, clear their own copies, which causes data loss. That reboot wipe is ElastiCache's own documented behaviour. The part AWS calls native comes after a promotion: the other replicas sync with the new primary, their content is deleted, and they reload the data from it. During that sync the replicas are not accessible, and the primary carries a temporary load increase; AWS says this "is native to Valkey and Redis OSS and isn't unique to ElastiCache Multi-AZ", so a self-hosted Sentinel failover inherits it too, which is why the configuration below resyncs one replica at a time. Separately, as a matter of engineering judgement, a self-hosted primary that restarts with no RDB or AOF file to reload comes back empty, and its replicas will resync from that empty dataset. TestFailover runs on up to 15 shards in any rolling 24-hour period, and AWS says it is not an operational tool for initiating failover.
Self-hosted, you choose between Sentinel and Cluster, and both replicate asynchronously. The Sentinel documentation asks for at least three Sentinels "in three different boxes" and states plainly that it "does not guarantee that acknowledged writes are retained during failures". The Cluster scaling guide says the same: it "can lose writes during the failover". WAIT does not rescue you — the command reference says it "does not make Redis a strongly consistent store". Sentinel's down-after-milliseconds defaults to 30 seconds; redis.conf ships cluster-node-timeout 15000.
# Listen for other Sentinels over TLS only. With tls-replication yes,
# Sentinel also uses TLS when it connects to the monitored primary.
port 0
tls-port 26379
tls-cert-file /etc/valkey/tls/sentinel.crt
tls-key-file /etc/valkey/tls/sentinel.key
tls-ca-cert-file /etc/valkey/tls/ca.crt
tls-replication yes
# ElastiCache: AWS promotes the least-lag replica. Here: two of three
# Sentinels must agree the primary is down.
sentinel monitor cache-primary 192.0.2.10 6379 2
# Sentinel authenticates as a dedicated ACL user. Since Valkey Sentinel 9.0
# that user needs +failover on every monitored instance, on top of the rest of
# the minimal ACL that sentinel.conf documents for the server side:
# user sentinel-user >somepassword +subscribe +publish +failover +script|kill \
# +ping +info +multi +slaveof +config +client +exec &__sentinel__:hello on
sentinel auth-user cache-primary sentinel-user
sentinel auth-pass cache-primary replace-with-secret-from-your-vault
# ElastiCache: detection timing is AWS's. Here: the 30 s default.
sentinel down-after-milliseconds cache-primary 30000
# The shipped example value: 3 minutes.
sentinel failover-timeout cache-primary 180000
# Resync one replica at a time so the others keep serving reads.
sentinel parallel-syncs cache-primary 1Patching, version lifecycle and the Extended Support bill
Serverless caches are patched automatically and transparently. Node-based clusters get a maintenance window, in which critical security updates are applied automatically; everything else arrives as a self-service update with a recommended window that runs from 14 days for critical patches to 90 days for low. Whether an update auto-applies after its due date is set by AWS by criticality, and "you cannot modify this value".
The version lifecycle is where the cost lives. On ElastiCache's end-of-life schedule, Redis OSS 4 and 5 caches not upgraded by the end of standard support on 31 January 2026 were automatically enrolled in Extended Support, with charges from 1 February 2026. Redis OSS 6 caches enroll if they are still running when its standard support ends on 31 January 2027. For provisioned Redis OSS nodes the pricing page sets that at an 80% premium in years one and two and 160% in year three, calculated on the on-demand node price — and the reserved-node discount does not apply to it.
Extended Support for versions 4 and 5 ends on 31 January 2029, after which AWS says any caches still running them "will be automatically upgraded to the latest version of Valkey". That is the whole bargain in one sentence: the managed version eventually decides your engine, too.
Self-hosted, there is no surcharge and no forced upgrade, which is not the same as no cost. You own the CVE watch, the rolling restart, and the discipline of not letting a version sit for years. Modelling that trade as a number is the method in pricing your exit.
What an auditor is shown
On ElastiCache, AUTH can only be enabled on clusters with in-transit encryption. All serverless caches must use RBAC, and only read-only ACL commands — ACL LIST, ACL WHOAMI, ACL USERS, ACL CAT — are supported; users and user groups are managed through the ElastiCache API. The evidence an auditor sees is therefore API and IAM evidence: who was permitted to call the user-management API.
Self-hosted, the evidence moves into files you control, and so does the burden of producing it. The equivalent package is an aclfile under version control with reviewed changes, TLS configuration showing port 0 so no plaintext listener exists, certificate lifecycle records, and the host-level access controls around the box. That is more work, and it is also auditable without anyone's console. The wider move, cache included, is laid out in the repatriation playbook.
The exit ramp: getting the data out
You cannot BGSAVE or REPLICAOF your way out, so the exit is AWS's backup export. It writes .rdb files to an S3 bucket, which must be in the same Region as the backup, and works for node-based Valkey and Redis OSS clusters and for serverless caches — but not for clusters using data tiering. The bucket must grant ElastiCache access first; AWS recommends a bucket policy over ACLs and publishes the policy on that page.
#!/usr/bin/env bash
set -euo pipefail
REGION="eu-west-1"
BUCKET="example-cache-exit" # same Region as the backup; ElastiCache granted access
EXPORT_NAME="orders-exit-2026-11"
# Node-based cluster: copy an existing backup into the bucket.
aws elasticache copy-snapshot \
--region "$REGION" \
--source-snapshot-name "orders-cache-manual-2026-11-03" \
--target-snapshot-name "$EXPORT_NAME" \
--target-bucket "$BUCKET"
# Serverless cache: the equivalent call takes a serverless snapshot name.
# aws elasticache export-serverless-cache-snapshot \
# --region "$REGION" \
# --serverless-cache-snapshot-name "orders-serverless-2026-11-03" \
# --s3-bucket-name "$BUCKET"
# The copy is asynchronous: poll for the .rdb objects, then fetch them.
# 60 x 30 s = 30 min is this script's give-up time, not an AWS completion SLA;
# a large copy may still be in progress, so check the bucket before retrying.
found=""
for _ in $(seq 1 60); do
if aws s3 ls "s3://${BUCKET}/${EXPORT_NAME}" --region "$REGION" | grep -q '\.rdb$'; then
found=1
break
fi
sleep 30
done
[ -n "$found" ] || { echo "no .rdb for ${EXPORT_NAME} in s3://${BUCKET}" >&2; exit 1; }
aws s3 cp "s3://${BUCKET}/" ./export/ --recursive \
--exclude "*" --include "${EXPORT_NAME}-*.rdb" --region "$REGION"Where to land it matters more than how. Valkey is compatible with Redis OSS 7.2 and earlier, and its migration guide says existing Redis client libraries connect without code changes — which makes self-hosted Valkey the low-risk landing for an ElastiCache export. The trap runs the other way: "Redis Community Edition (CE) version 7.4 and later produce data files that are not compatible with Valkey." Neither project documents whether a Valkey 8 or 9 file loads into Redis 8, so test that load before relying on it.
The seed config's job is to make every inherited behaviour explicit, so nothing shifts at cutover. One ordering detail comes straight from valkey.conf: if AOF is enabled at startup the server loads the AOF, not the RDB. Boot the seed with appendonly no so it loads the exported file, then convert on the live server.
# TLS only, no plaintext listener. ElastiCache: AUTH requires in-transit encryption.
bind 192.0.2.10 127.0.0.1
protected-mode yes
port 0
tls-port 6379
tls-cert-file /etc/valkey/tls/valkey.crt
tls-key-file /etc/valkey/tls/valkey.key
tls-ca-cert-file /etc/valkey/tls/ca.crt
tls-auth-clients optional
tls-replication yes
# ElastiCache: users via the API. Here: a reviewed file in version control.
aclfile /etc/valkey/users.acl
# ElastiCache: reserved-memory-percent 25% on node-based clusters.
# Here: on a 16 GB host, leave the same quarter as headroom deliberately.
maxmemory 12gb
# ElastiCache default, kept on purpose so TTL keys are evicted the way the
# application expects. The upstream default would be noeviction.
maxmemory-policy volatile-lru
# Place the exported .rdb here as dump.rdb before first start.
dir /var/lib/valkey
dbfilename dump.rdb
save 3600 1 300 100 60 10000
# ElastiCache for Redis OSS: AOF and Multi-AZ are mutually exclusive.
# Here: boot with AOF off so the RDB loads, then on the live server run
# CONFIG SET appendonly yes, followed by CONFIG REWRITE.
appendonly no
appendfsync everysecThen dual-run: point a read-only canary at the new node, compare key counts and TTLs, and cut writers over in a window you chose. If you ever need to go back, the reverse path has its own rule — ElastiCache cannot seed a cluster-mode-disabled cluster from an .rdb produced by a cluster-mode-enabled one. The same discipline of testing the exit before needing it runs through the OpenSearch fork migration.
Who is on call decides it
ElastiCache is a reasonable trade when nobody on the team wants a cache pager and the application can live with AWS's defaults, AWS's patch calendar and AWS's eventual engine choice. Self-hosted Valkey or Redis is the right trade when the licence, the version cadence and the failover behaviour are things the organisation needs to decide for itself — and is willing to staff.
Either way, the long-game move is the same and costs an afternoon: write the defaults down. Export the parameter group, state the eviction policy and memory headroom in a config file you own, and keep a tested .rdb export path. A cache built that way can change hosts in a decade without changing behaviour.
§FAQ/Common questions
Frequently asked
Is ElastiCache the same as Redis?
No. ElastiCache is AWS's managed hosting service. It runs Valkey (ElastiCache versions 7.2.6 to 9.1) and Redis OSS up to its version 7.1 label, which AWS says is compatible with Redis OSS 7.0. It sets its own parameter defaults, such as maxmemory-policy volatile-lru, and restricts commands such as CONFIG, BGSAVE and REPLICAOF.
What is the default eviction policy on ElastiCache?
volatile-lru: when memory is full, keys with a TTL are evicted by least-recently-used estimate. On node-based clusters you can change it in a custom parameter group; on serverless caches it is fixed. Upstream Valkey and Redis default to noeviction, which returns errors on writes instead.
Can ElastiCache lose data during failover?
With durability disabled, the default, yes: replication is asynchronous and AWS says a small amount of data might be lost. On Valkey 9.0+ with durability enabled, AWS says synchronous writes mean zero data loss and asynchronous writes may lose up to 10 seconds, with narrow instance and cluster-mode requirements.
How do I migrate from ElastiCache to self-hosted Valkey?
Export a backup as .rdb to an S3 bucket in the same Region with copy-snapshot (node-based) or export-serverless-cache-snapshot (serverless), download it, and seed a Valkey node configured to restate the ElastiCache defaults you rely on. Data-tiering clusters cannot export, and Redis CE 7.4+ files do not load into Valkey.
Executive Briefing
Thirty minutes to clarify your infrastructure risk
Walk us through your vendor footprint and regulatory constraints. We will tell you honestly where sovereignty creates leverage — and where it does not. No pitch deck. No obligation.