Redis vs Valkey: Which Should You Use for Your Next Project?

Redis vs Valkey in 2026: licensing, client compatibility, the RDB format wall, measured performance and a migration path that actually works.

Valkey is a drop-in replacement for Redis — until you try to move your data. This comparison separates the parts that really are drop-in (protocol, clients, config) from the parts that are not (persistence files), with measured numbers instead of vendor claims. Verified 2026-09-28.

The one-line answer

  • Valkey — BSD-3 licensed, Linux Foundation governed, wire-compatible with Redis OSS 7.2 and older. Choose it if licensing, vendor neutrality or AWS ElastiCache pricing matter to you.
  • Redis — tri-licensed (RSALv2 / SSPLv1 / AGPLv3), faster release cadence, ships search and JSON in core since 8.0. Choose it if you want the feature velocity and AGPLv3 is acceptable.

Both speak RESP2/RESP3, so your application code does not care. The decision is licensing, managed pricing, and how much it costs you to move data.

What actually happened

In March 2024 Redis changed its license away from BSD. The Linux Foundation forked the last BSD commit as Valkey (7.2.4). Redis later added AGPLv3 as a third option starting with Redis 8, so it is OSI-approved open source again — but under a copyleft license, not a permissive one.

Then came the part that surprises people: Redis 7.4 bumped the RDB persistence format from version 11 to version 12, and later releases kept going. That change, not the license, is what actually blocks migrations today.

License and governance

Valkey Redis
License BSD-3-Clause RSALv2, SSPLv1 or AGPLv3 (choose one)
OSI-approved Yes Yes (AGPLv3 only)
Copyleft No AGPLv3 is copyleft
Governance Linux Foundation, vendor-neutral Redis Ltd.
Contributors AWS, Google, Oracle, Ericsson, others Redis Ltd. plus community
Current stable (2026-09-28) 9.1.2 (2026-09-01) 8.10.2 (2026-09-17)

The practical question for a solo developer or small business: will a future license change affect you? Under AGPLv3 you must publish modifications if you offer the modified software as a network service. Running it unmodified behind your app is fine. Under BSD-3 you have no such obligation.

Rule of thumb: if you are embedding a cache in a product you distribute, BSD-3 removes an entire category of legal review.

Client libraries: genuinely drop-in

I tested ioredis 6.0.0 and node-redis 6.2.1 against both Redis 8.10.2 and Valkey 9.1.2 with identical code, including pipelines, MULTI/EXEC and RESP3 negotiation.

Client Redis 8.10.2 Valkey 9.1.2
ioredis 6.0.0 OK OK
node-redis 6.2.1 (RESP3) OK OK
pipeline / multi OK OK

Switching the client from one to the other is a connection-string change, nothing more.

One gotcha: Valkey reports redis_version:7.2.4 in INFO for backward compatibility. Code that branches on redis_version will conclude it is talking to a 2024 Redis.

docker exec my-valkey valkey-cli INFO server | grep -E 'server_name|valkey_version|redis_version'
# server_name:valkey
# redis_version:7.2.4        <- lie, kept for compatibility
# valkey_version:9.1.2       <- the truth

Detect Valkey with server_name and valkey_version. Never with redis_version.

The RDB wall

This is the section that matters, because it is where “drop-in replacement” stops being true.

Replication compatibility (measured)

A replica loads its primary’s snapshot, so replication is a direct test of format compatibility. Primary on the left, replica on the right:

Primary Replica Result
Redis 7.2.16 Valkey 9.1.2 master_link_status:up — all keys transferred
Redis 7.4.11 Valkey 9.1.2 failed — Can't handle RDB format version 12
Redis 8.10.2 Valkey 9.1.2 failed — Can't handle RDB format version 15
Redis 8.10.2 Valkey 8.1.10 failed — Can't handle RDB format version 15
Valkey 9.1.2 Redis 8.10.2 up — all keys transferred
Valkey 9.1.2 Valkey 8.1.10 up
Valkey 9.1.2 Valkey 9.1.2 up

Two things to take from this:

  1. Redis 7.2 and older migrate to Valkey cleanly. Redis 7.4 and newer do not migrate at all, by file or by replication.
  2. Valkey can go back to Redis. The migration is one-directional in practice: Valkey negotiates a compatible format with an older replica; Redis does not.

DUMP/RESTORE does not save you

The obvious workaround — copy keys one by one with DUMP/RESTORE — fails for the same reason. The payload carries the RDB version and has no magic string to override. Tested with five key types (string, hash, list, sorted set, key with TTL):

source \ destination redis 7.2 redis 7.4 redis 8.10 valkey 8.1 valkey 9.1
redis 7.2 OK 5/5 OK 5/5 OK 5/5 OK 5/5 OK 5/5
redis 7.4 FAIL OK 5/5 OK 5/5 FAIL FAIL
redis 8.10 FAIL FAIL OK 5/5 FAIL FAIL
valkey 8.1 OK 5/5 OK 5/5 OK 5/5 OK 5/5 OK 5/5
valkey 9.1 FAIL FAIL FAIL FAIL OK 5/5

Note the diagonal: everything reads its own format. Note also that valkey 9.1 → valkey 8.1 fails, even though replication between those two versions succeeds. DUMP has no version negotiation; replication does.

Failure message: ERR DUMP payload version or checksum are wrong.

Why it works this way

From Valkey’s own source (src/rdb.h):

/* RDB 11 is the last open-source Redis RDB version, used by Valkey 7.x and 8.x.
 *
 * RDB 12-79 are reserved for Redis non-compatible RDB formats
 *
 * We start using high rdb version numbers since Valkey 9.0... */
#define RDB_VERSION 81
#define RDB_FOREIGN_VERSION_MIN 12
#define RDB_FOREIGN_VERSION_MAX 79

Valkey deliberately reserves versions 12–79 for formats it refuses to guess at, and numbers its own from 80 upward to avoid collisions. This is a design decision, not a bug, and it is not going to be “fixed” in a patch release.

What each build actually writes, confirmed from the file header:

Build RDB magic written
Redis 7.2.16 REDIS0011
Redis 7.4.11 REDIS0012
Redis 8.10.2 REDIS0015
Valkey 8.1.10 REDIS0011
Valkey 9.0.6 / 9.1.2 VALKEY080

How to migrate

Check which case you are in first:

docker exec my-redis redis-cli INFO server | grep redis_version

Case 1 — Redis 7.2 or older: copy the snapshot

Both servers understand RDB 11, so this is a plain upgrade.

# 1. Quiesce writes, then snapshot the source
docker exec my-redis redis-cli CONFIG SET save ""
docker exec my-redis redis-cli SHUTDOWN NOSAVE   # or SAVE then stop
docker cp my-redis:/data/dump.rdb ./dump.rdb

# 2. Start Valkey with that file in place
docker run -d --name my-valkey -v "$PWD:/data" valkey/valkey:9.1.2-alpine \
  valkey-server --dir /data --save 60 1 --appendonly yes

# 3. Verify the key count matches what the source had
docker exec my-valkey valkey-cli DBSIZE
docker exec my-valkey valkey-cli INFO keyspace

Zero-downtime alternative: run Valkey as a replica of Redis 7.2, wait for master_link_status:up, point the app at Valkey, then REPLICAOF NO ONE.

docker exec my-valkey valkey-cli REPLICAOF <redis-ip> 6379
docker exec my-valkey valkey-cli INFO replication | grep master_link_status
# ... repoint the application ...
docker exec my-valkey valkey-cli REPLICAOF NO ONE

Case 2 — Redis 7.4 or newer: no direct path

Both the file copy and replication routes are closed, and DUMP/RESTORE is closed too. Your options:

  1. Application-level migration. Read through the app or a SCAN loop using type-specific commands (GET/SET, HGETALL/HSET, LRANGE/RPUSH, ZRANGE with scores), and write to Valkey. Slow, but it works regardless of versions and is the only route with no third-party dependency.
  2. A dedicated migration tool. Community converters exist for exactly this case. I did not verify a specific tool end to end, so treat any of them as unverified until you have tested the round trip on a copy of your data.
  3. Dual-write and cut over. Write to both for a period, then flip reads. The safest option if the cache is reconstructible and you can tolerate a cold period — and often the correct answer for a pure cache, where you can simply start empty.

If your data is a cache and not a store: do not migrate it. Start Valkey empty, let it warm up, and move on. This turns the whole problem into a one-line config change.

Case 3 — Valkey back to Redis

Replication works (see the matrix above), but the file-copy route does not: a VALKEY080 snapshot is refused by every older server, including Valkey 8.x, not just Redis.

Snapshot Loads into Redis 7.2–8.10 Loads into Valkey 8.0/8.1 Loads into Valkey 9.0/9.1
REDIS0011 (Redis 7.2, Valkey 8.x) yes yes yes
REDIS0012 (Redis 7.4) Redis 7.2 no, Redis 7.4+ yes no no
REDIS0015 (Redis 8.10) Redis 8.10 yes only no no
VALKEY080 (Valkey 9.0/9.1) no — Wrong signature trying to load DB from file no — Can't handle RDB format version 80 yes

So the migration routes are not equally wide:

  • Redis 7.2 → anything: file copy, replication, or DUMP/RESTORE. All three work.
  • Redis 7.4+ → Valkey: no route. Neither file, nor replication, nor DUMP/RESTORE.
  • Valkey 9 → Valkey 8.1 (downgrade): replication works, file copy does not. Replicate first, then REPLICAOF NO ONE; never hand it the RDB.
  • Valkey 9 → Redis 8.10: replication works, file copy does not.

The reason the copy fails where replication succeeds is that replication negotiates a compatible snapshot for the replica, while a file on disk has no one to negotiate with — the loader simply reads the version number and refuses.

One more thing worth knowing: Valkey 9.0 and 9.1 both write VALKEY080 and read each other’s snapshots fine, so patch upgrades inside 9.x are a plain file swap. The wall is at major-version boundaries, not at every release.

Performance: measured, with big caveats

Benchmarked in containers limited to 2 vCPU and 2 GB, 50 clients, no persistence, io-threads 2, on one host. I ran the suite three times; the ranges below span every run. Requests per second, p50 in ms for the P=1 rows:

Test Redis 8.10.2 Valkey 9.1.2 Redis 7.4.11
SET, P=1 47–52k (0.47–0.52) 43–49k (0.41–0.44) 25–43k (0.90)
GET, P=1 48–62k (0.39–0.50) 44k (0.41–0.42) 41–44k (0.46–0.52)
LPUSH, P=1 63k (0.39) 43–47k (0.39–0.62) 50–54k (0.39–0.79)
SET, P=16 476–585k 360–746k 324–333k
GET, P=16 641–917k 581–781k 448–730k
LPUSH, P=16 311–444k 241–315k 254–312k
INCR, P=16 — 649k (one run) —

Do not treat the middle columns as a ranking. The spread within a single server is larger than the spread between servers: Valkey 9.1.2 SET P=16 measured 360k, 493k and then 746k across three runs — a 2.1x range on identical configuration and identical hardware. That is a shared-host container benchmark measuring the host as much as the server.

What survived every run:

  • Redis 8.10.2 beats Valkey 9.1.2 on LPUSH P=16 — 311–444k against 241–315k. The only per-operation gap that held consistently in one direction.
  • Redis 7.4.11 is the slowest of the three on SET — 324–333k at P=16, below both 8.x/9.x lines in every run.
  • Everything else overlaps. Redis 8.10.2 and Valkey 9.1.2 traded places on SET P=16 and GET P=16 depending on the run.

I originally wrote that Redis 8.10 was “at least level with Valkey on these operations” and that Redis 7.4 was “clearly slower on writes”. A second run did not support either claim — Valkey won SET P=16 outright in the third pass, and Redis 7.4 matched or beat Redis 8.10 on LPUSH. The corrected position: there is no defensible performance argument for choosing between these two, and if you need a real answer for your workload you must benchmark on a dedicated instance with your own key sizes and access patterns.

# Benchmark your own instance properly — pinned, dedicated, realistic payloads
valkey-benchmark -h 127.0.0.1 -p 6379 -a "$REDIS_PASSWORD" \
  -n 1000000 -c 50 -P 16 -d 512 -t set,get,lpush,incr -q

Managed pricing: the concrete saving

Where Valkey is unambiguously cheaper is a managed cache. AWS ElastiCache prices Valkey below Redis OSS on both models:

Valkey Redis OSS
Node-based 20% cheaper baseline
Serverless data $0.084 / GB-hour $0.125 / GB-hour
Serverless compute $0.0023 / million ECPU $0.0034 / million ECPU
Serverless minimum data 100 MB 1 GB

Serverless storage and compute are both roughly 33% cheaper, and the minimum metered floor is ten times smaller. Backups are $0.085 per GiB-month for either engine. Redis OSS also carries extended-support surcharges (+80% in years 1–2, +160% in year 3) once a version goes EOL, which Valkey does not.

For an existing reserved Redis OSS node, AWS allows an engine swap that keeps the reservation at 20% more value.

Feature differences worth knowing

Valkey 9.x added capabilities Redis OSS 7.2 never had:

  • Hash field expiration — HEXPIRE, HTTL, HPERSIST, HGETEX, HGETDEL. Per-field TTLs inside a hash, which previously required a second key and a cleanup job.
  • MSETEX — multi-key set with expiry in one round trip, atomically.
  • SCAN in cluster mode, numbered databases in cluster mode, atomic slot migration.

If you are currently emulating per-field TTLs with a side key, that alone justifies Valkey 9.

The reverse: Redis 8.x bundles search, JSON, time series and probabilistic types in core (FT.SEARCH, JSON.SET). Check command availability before committing to either — I confirmed Valkey 9.1.2 has the hash-field commands above and does not have HOTKEYS, ACL ROLES, XACKDEL, JSON.SET, FT.SEARCH or VSIM; those are 9.2-rc1 or Redis-specific.

# Quick capability probe — run this against your own target before migrating
for c in HEXPIRE HGETEX MSETEX JSON.SET FT.SEARCH; do
  printf '%-10s %s\n' "$c" "$(docker exec my-valkey valkey-cli $c 2>&1 | head -1)"
done

ERR wrong number of arguments means the command exists. ERR unknown command means it does not.

Our recommendation

Our recommendation for a new self-hosted project in 2026

Valkey 9.1 on a small VPS. BSD-3 removes license review, clients and config files are compatible with everything you already know, and the hash-field expiration commands replace hand-rolled cleanup jobs. Pick the pinned tag, not latest:

# docker-compose.yml
services:
  cache:
    image: valkey/valkey:9.1.2-alpine
    command: >
      valkey-server
      --appendonly yes
      --appendfsync everysec
      --maxmemory 512mb
      --maxmemory-policy allkeys-lru
      --requirepass ${REDIS_PASSWORD}
    volumes:
      - valkey-data:/data
    restart: unless-stopped

volumes:
  valkey-data:

Our recommendation when you are already on Redis 8 and it works

Stay on Redis 8. There is no performance argument for moving, AGPLv3 is a genuine open-source license, and — as the matrix above shows — your data cannot be migrated to Valkey directly anyway. Moving now costs you a rebuild of the cache at best, and a custom migration script at worst, for no measurable gain.

Our recommendation if you are on a managed cache

Valkey, for pricing. On ElastiCache that is 20% off nodes and roughly 33% off serverless, with a 100 MB minimum instead of 1 GB.

Cost

Self-hosted, the software is free either way. The bill is the box, and both fit on the same one:

Line item Valkey Redis
Valkey 9.1.2 / Redis 8.10.2 $0 $0
VPS (2 vCPU / 4 GB, 2 GB given to the cache) ~€5.99–6.49/mo same
Managed cache (ElastiCache, node-based, smallest) ~20% below Redis OSS baseline
Managed serverless, 1 GB stored ~$61/mo at $0.084/GB-hr ~$91/mo at $0.125/GB-hr

Assumptions: 1 GB of resident data, ~1 vCPU-equivalent of steady compute, EU region, on-demand, no reserved commitment. Serverless figures are storage-dominated; compute adds ECPU charges on top. Verify current prices before budgeting — both vendors change them without notice.

Common problems

  • Can't handle RDB format version 12 / 15 — you are migrating from Redis 7.4 or newer. There is no flag for this. See Case 2.
  • Can't handle RDB format version 80 — a Valkey 9 snapshot handed to Valkey 8.x, or to any Redis. Replicate instead of copying the file.
  • Wrong signature trying to load DB from file — a VALKEY080 file loaded by an older Redis, which rejects the magic string before it even reads the version.
  • ERR DUMP payload version or checksum are wrong — same wall, hit through DUMP/RESTORE. Not a checksum problem despite the wording.
  • Monitoring reports the wrong Redis version — Valkey’s INFO says redis_version:7.2.4. Read server_name and valkey_version instead.
  • A library refuses to start against Valkey — some clients run a version gate on redis_version. Both major Node.js clients were fine in testing; a pinned legacy client may not be.
  • Pulling latest and getting a format bump — pin the tag. A major-version jump can change the RDB version your backups are written in, which is the same trap one release later.
  • Assuming the migration is reversible — it is not symmetric. Valkey reads Redis 7.2 and older; Redis reads neither Valkey’s format nor Redis 7.4+’s.

Conclusion

Valkey and Redis are the same protocol, the same client libraries and the same config format. They are not the same persistence format, and that asymmetry — one-directional, deliberate, and documented only in a source comment — is the single thing most likely to break your migration.

For a new project, Valkey’s BSD-3 license and 20–33% managed-cache discount make it the default. For an existing Redis 8 deployment, do nothing: the performance difference is inside the noise, and the data cannot come with you.

Related guides