From Redis 7 to Redis 8.x and Valkey 9: What's New, Where They Diverge and Migrating StackExchange.Redis 2→3
Neither Redis 7.4 nor Valkey 9 can open an RDB file written by Redis 8; Redis and Valkey share 7.2 as their common ground, and upgrades are one-way. With real measurements: RDB and replication compatibility, a summary of Redis 8.0–8.10, a compatibility table built by asking both servers with COMMAND DOCS, old APIs that are compile errors in StackExchange.Redis 3.x, and a version upgrade plan.
Version note: The examples in this post were run with Redis 8.10.3 (redis:8), Redis 7.2.17 and 7.4.12, Valkey 9.1.3, .NET 10 and StackExchange.Redis 3.4.35.
Guess First
The simplest way to move the Redis of Bookstore, the online bookstore used as the shared example across this site's series, from one version to another, or from Redis to Valkey, seems to be taking the RDB file and opening it on the new server. lab/upgrade/rdb-compat.sh writes three keys with one image, runs SAVE, and tries to open the resulting dump.rdb with another image. Which of the eight combinations open?
sh lab/upgrade/rdb-compat.sh
redis:7.2 -> redis:8 REDIS0011 loaded, DBSIZE 3
redis:7-alpine -> redis:8 REDIS0012 loaded, DBSIZE 3
redis:8 -> redis:7-alpine REDIS0015 FAILED: 12:24:23.740 # Can't handle RDB format version 15
redis:7.2 -> valkey/valkey:9 REDIS0011 loaded, DBSIZE 3
redis:7-alpine -> valkey/valkey:9 REDIS0012 FAILED: 12:24:35.101 # Can't handle RDB format version 12
redis:8 -> valkey/valkey:9 REDIS0015 FAILED: 12:24:40.929 # Can't handle RDB format version 15
valkey/valkey:9 -> redis:8 VALKEY080 FAILED: 12:24:46.628 # Wrong signature trying to load DB from file
valkey/valkey:9 -> redis:7.2 VALKEY080 FAILED: 12:24:52.262 # Wrong signature trying to load DB from file
Only three paths are open: from an older Redis to a newer Redis, and from Redis 7.2 to Valkey 9. The first 9 bytes of the file tell the format: Redis 7.2 writes REDIS0011, 7.4 (redis:7-alpine, 7.4.12) REDIS0012, 8.10.3 REDIS0015, while Valkey 9 now uses its own signature, VALKEY080. Upgrading is one-way: 7.4 cannot open a file written by Redis 8, so a plan of "if something goes wrong I'll go back to the old version" does not work through RDB. Redis and Valkey have 7.2 in common; after that there are two separate roads. In this last post of the series we cover those two roads: what came from Redis 7 to 8.10 version by version, where Valkey 9 diverges with the compatibility table this post measured, migrating StackExchange.Redis from 2 to 3, and a version upgrade plan.
From Redis 7 to 8.10: Version by Version
The table below is compiled only from the headline items in Redis's official release notes and from features we used in this series; the since values of the commands were verified with COMMAND DOCS on 8.10.3.
| Version (GA) | Highlights | In the series |
|---|---|---|
| 7.4 (2024) | Hash field expiration (HEXPIRE, HTTL); switch to the RSALv2/SSPLv1 licence | 04 |
| 8.0 (May 2025) | JSON, Query Engine, time series and probabilistic structures in the core distribution; vector set (beta); HGETEX, HSETEX, HGETDEL; AGPLv3 option | 04, 07, 11 |
| 8.2 (August 2025) | XDELEX, XACKDEL; new BITOP operators; CLUSTER SLOT-STATS | 10 |
| 8.4 (November 2025) | SET … IFEQ, DELEX, DIGEST, MSETEX; XREADGROUP … CLAIM; atomic slot migration; FT.HYBRID | 03, 10, 13 |
| 8.6 (February 2026) | XADD … IDMP; allkeys-lrm/volatile-lrm; HOTKEYS; memory reduction for hashes and sorted sets | 06, 10, 12 |
| 8.8 (May 2026) | Array type; INCREX; XNACK; AGGREGATE COUNT; keyspace notifications at hash field level | 06, 07, 08, 09, 10 |
| 8.10 (July 2026) | Compact hashes and HIMPORT; LMOVEM; SUNIONCARD, SDIFFCARD; BACKUP; XREADGROUP … MAXCOUNT/MAXSIZE; JSONPath extensions | 04, 05, 10, 11, 12 |
A minor version comes out every six months or so, and each adds a few commands; a significant part of the commands used in this series belongs to after 8.0. In practice: if a managed service or the image your company has approved is a few minor versions behind, part of what we covered post by post is not there. StackExchange.Redis offers typed methods for these commands (the 3.3.0 notes took the 8.10 bindings out of preview), but if the server is older, the command fails at run time with ERR unknown command or a syntax error; the package does not check the server version for you.
8.12 is currently at the RC stage: the first candidate came out on 29 October and the third on 12 November. The notes of the first candidate list commands that give set members their own expiration (SEXPIRE, STTL and similar) and compressed bitmaps brought into the Redis core. Do not put it into a production plan before GA; the release notes themselves mark RCs as not suitable for production.
A Compatibility Table from Measurements
Valkey split off from Redis 7.2.4 and still reports redis_version:7.2.4 in INFO (we saw this in post 02), so a tool that decides by "Redis version 7.2" sees Valkey 9 the same way. I asked the servers rather than the documentation which command exists where: the compat command sends COMMAND DOCS to both servers for each command and prints the since field (-: the server does not know the command); for options it runs the command:
dotnet run --project src/Bookstore.RedisLab -- compat
command Redis 8.10.3 Valkey 9.1.3
HEXPIRE 7.4.0 9.0.0
HGETEX 8.0.0 9.0.0
HSETEX 8.0.0 9.0.0
HGETDEL 8.0.0 9.1.0
VADD 8.0.0 -
JSON.SET 1.0.0 -
FT.SEARCH 1.0.0 -
BF.ADD 1.0.0 -
XACKDEL 8.2.0 -
DELEX 8.4.0 -
DIGEST 8.4.0 -
MSETEX 8.4.0 9.1.0
HOTKEYS 8.6.0 -
XCFGSET 8.6.0 -
INCREX 8.8.0 -
XNACK 8.8.0 -
ARSET 8.8.0 -
HIMPORT 8.10.0 -
LMOVEM 8.10.0 -
SUNIONCARD 8.10.0 -
SDIFFCARD 8.10.0 -
BACKUP 8.10.0 -
DELIFEQ - 9.0.0
COMMANDLOG - 8.1.0
SET ... IFEQ ok ok
XADD ... IDMP ok ERR Invalid
ZUNIONSTORE ... AGGREGATE COUNT ok syntax error
Two things to watch while reading it: the 1.0.0 shown for JSON.SET, FT.SEARCH and BF.ADD is the module's own version number; these modules entered the core distribution with Redis 8.0. In Valkey they come in the separate valkey-bundle image, and as we saw in post 11 they behave differently. Second, some shared features arrived at different times: hash field expiration came in Redis 7.4 and in Valkey 9.0. A summary of the differences we measured across the series: for string compare-and-set Valkey has SET … IFEQ and DELIFEQ but no DELEX/DIGEST (03); streams have no CLAIM, IDMP or XNACK (10); probabilistic structures, JSON and search are separate modules (07, 11); ACLs have no module categories such as @json (14); there is no BACKUP, HOTKEYS or allkeys-lrm (12).
Valkey's Own Road
The divergence goes both ways: Valkey has features Redis does not. DELIFEQ and COMMANDLOG (a log that records large requests and replies as well as slow commands) in the table are two of them. In post 13 we ran Valkey 9's atomic slot migration with CLUSTER MIGRATESLOTS on the source node; Redis's CLUSTER MIGRATION IMPORT runs on the destination node: the same idea, a different command. Valkey 9 also has multiple databases in a cluster, but only if cluster-databases is raised at startup. The file format has split too: Valkey 9's RDB carries the VALKEY080 signature, and Redis rejects it with "wrong signature". Valkey's next version, 9.2, is currently at the RC stage.
A practical view for choosing: if you use Redis 8's commands (especially the string, stream and hash additions after 8.4) or the JSON/Query Engine in the core, moving to Valkey means code changes. Where the licence (the RSALv2/SSPLv1/AGPLv3 options we described in post 01 versus Valkey's BSD licence) or the managed service (ElastiCache's move towards Valkey, Azure Managed Redis) is the deciding factor, building the list of commands the application uses by asking both servers, as in this post, shortens the discussion.
StackExchange.Redis from 2 to 3
StackExchange.Redis 3.0.0 came out in June 2026, and the release notes now live on GitHub (the package's GitHub organisation also changed to seredis). Things to check when moving from 2.x, from the release notes:
- 3.0.0: the IO layer was rewritten, the public API is the same as 2.13.17; the default protocol is RESP3. The one deliberate behaviour change:
Execute[Async]now recognises admin commands; unlessallowAdminis on,FLUSHALLis refused in the client (we saw this forKEYSin post 02 and forINFOin post 12). - 3.1.0: client-side geographic failover; old APIs that were announced for removal in 3.0 turned from warnings into compile errors.
- 3.2.0: the .NET 6 target was dropped (it runs through .NET Standard, without Unix domain socket support); the cluster topology is read from
CLUSTER SLOTS. - 3.4.0: under RESP3, a separate pub/sub connection is the default again (in post 09 we saw a 40 MB reply drop the shared connection); faster recovery from a cluster failover.
To see the compile errors, I compiled a few lines familiar from the 2.x days against 3.4.35:
Console.WriteLine(server.IsSlave);
Console.WriteLine(CommandFlags.PreferSlave);
mux.PreserveAsyncOrder = false;
await server.SlaveOfAsync(null);
Console.WriteLine(ConfigurationOptions.Parse("localhost").ResponseTimeout);
Program.cs(5,19): error CS0619: 'IServer.IsSlave' is obsolete: 'Starting with Redis version 5, Redis has moved to 'replica' terminology. Please use IsReplica instead, this will be removed in 4.0.'
Program.cs(6,19): error CS0619: 'CommandFlags.PreferSlave' is obsolete: 'Starting with Redis version 5, Redis has moved to 'replica' terminology. Please use PreferReplica instead, this will be removed in 4.0.'
Program.cs(7,1): error CS0619: 'ConnectionMultiplexer.PreserveAsyncOrder' is obsolete: 'Not supported; if you require ordered pub/sub, please see ChannelMessageQueue, will be removed in 4.0'
Program.cs(8,7): error CS0619: 'IServer.SlaveOfAsync(EndPoint, CommandFlags)' is obsolete: 'Starting with Redis version 5, Redis has moved to 'replica' terminology. Please use ReplicaOfAsync instead, this will be removed in 4.0.'
Program.cs(9,19): error CS0619: 'ConfigurationOptions.ResponseTimeout' is obsolete: 'This setting no longer has any effect, and should not be used - will be removed in 4.0.'
The 3.1.0 note says these APIs will be removed "in 3.2"; the messages in 3.4.35 say "4.0". Every error message names the replacement: IsReplica, PreferReplica, ReplicaOfAsync, and for ordered pub/sub the ChannelMessageQueue from post 09. On top of these, the 3.x analyzers warn at build time: SER307 for sync-over-async in post 02, SER305 for awaiting a transaction's task early in post 08. Do not silence these warnings during the migration; fix them. 4.0 is currently available on NuGet as alpha releases.
A Version Upgrade Plan
Since the RDB file is one-way, the safe road is replication: start the new version as a replica of the old primary, let it synchronise, then promote the new version to primary. lab/upgrade/repl-compat.sh tried this with four combinations:
redis:7-alpine -> redis:8 master_link_status:up, GET=42
redis:7.2 -> valkey/valkey:9 master_link_status:up, GET=42
redis:8 -> valkey/valkey:9 master_link_status:down, GET=nil 12:26:22.572 # Failed to load RDB
redis:8 -> redis:7-alpine master_link_status:down, GET=nil 12:26:34.329 # Failed trying to load the MASTER synchronization DB from disk, check server logs.
Because replication also sends an RDB in the first synchronisation, it gave the same result as the RDB table: Redis 7.4 → 8 and Redis 7.2 → Valkey 9 work, Redis 8 → Valkey 9 and backwards Redis 8 → 7.4 do not. For someone who wants to move from Redis 8 to Valkey there is neither a file nor a replication path; the data has to be moved at the application level (reading and writing key by key). The lab scripts run in Linux containers; on Windows they can be run with the sh command from Git Bash or WSL.
The plan, in order: try the commands you use on the target version (a list like compat, and the Testcontainers tests from post 14); check the target version's release notes for changed config defaults and the "Known bugs and limitations" section; update StackExchange.Redis first, in a separate step from the server, so the effects of the two changes do not mix; review the Functions library and the ACL rules (new command categories); upgrade on staging with a replica; in production add the new version as a replica, watch master_link_status:up and the replication lag, and promote it with a failover (plan for the failover time we saw in post 13); do not keep the old node as a replica afterwards, because it cannot read the new primary's RDB. The way back is the old version's backup plus accepting the loss of writes made after that backup; write this down before upgrading.
In Production
Treat patch releases (such as 8.10.1 → 8.10.3) separately from minor versions: patches are security and bug fixes, they do not change the RDB format, and they should be applied quickly (post 14). Minor versions (8.8 → 8.10) bring new commands and configuration; they should be planned with the application team. If you use a managed service, verify which Redis or Valkey version it runs from the service's documentation rather than from INFO server; Valkey's redis_version:7.2.4 report and Azure Managed Redis's Redis Enterprise base can make that information misleading. Pin the image tag to an exact version such as redis:8.10.3 instead of a floating tag like redis:8; in this series the lab used a floating tag, the tests (post 14) an exact version.
Common Pitfalls
Assuming you can go back to the old version with an RDB after upgrading: 7.4 could not open Redis 8's file.
Trying to move Redis 8 data to Valkey with a file or replication: both were rejected.
Making feature decisions based on Valkey's redis_version:7.2.4 report.
Assuming module commands (JSON.*, FT.*, BF.*) exist on every Redis-compatible server.
Not testing the RESP3 default and the admin check in Execute when moving to StackExchange.Redis 3.
Taking an RC release into production.
Using floating image tags in the lab and in production: one day redis:8 will pull 8.12.
A Small Experiment
★☆☆ Add other commands you used in this series to the compat list (XAUTOCLAIM, FCALL, SSUBSCRIBE, GEOSEARCH) and run it against both servers. Which ones are shared?
★★☆ Add pairs with valkey/valkey:8 and redis:7.2 to rdb-compat.sh. What is the signature of the file Valkey 8 writes, and can Redis 7.2 open it?
★★★ Run Bookstore.Api and Bookstore.Worker against Valkey 9.1.3 (ConnectionStrings__Redis=localhost:6380) and try every endpoint. Which endpoints fail? For each, write an alternative that works on Valkey, and make the application choose the right path depending on the server type.
This is where the series ends. In fifteen posts we built Redis up as more than a cache: a data structure server carrying Bookstore's counters, carts, bestsellers, stock reservations, order events and catalog search, keeping apart at every step what was verified by measurement and what came from the documentation.