Redis Stack is at the end of its road. The redis-stack repository says maintenance releases for 6.2, 7.2, and 7.4 stopped in December 2025, and the last builds (7.2.0-v20 and 7.4.0-v8) shipped on 3 November 2025. Teams that want an open source path are looking at valkey-bundle, the Valkey image that ships valkey-search, valkey-json, valkey-bloom, and valkey-ldap. The first attempt is usually to copy dump.rdb across, and it ends with Valkey logging The RDB file contains AUX module data I can't load: no matching module 'ft_index0' and exiting. This guide covers what carries over from RediSearch, RedisJSON, and RedisBloom, what you rebuild, which commands change, and a cutover runbook.
- A Redis Stack snapshot does not load into valkey-bundle. Redis 7.4 and later write RDB 12 or newer, and any Redis Stack file written while RediSearch was loaded carries
ft_index0data that Valkey exits on. Plan a logical move. - JSON is the closest match: valkey-json registers the same type name,
ReJSON-RL, and reads encoding version 3.JSON.MERGEis missing from valkey-json 1.0.3, the version in every current bundle. - Bloom filters move only by re-inserting the source items. valkey-bloom has its own type, no
BF.SCANDUMP, and no cuckoo, Count-Min, Top-K, or t-digest. There is no Valkey time series or graph module. - Search indexes are always rebuilt with
FT.CREATE. valkey-search 1.2 targets RediSearch 2 behavior for Dialect 2 queries, but has noFT.CONFIG,FT.ALTER, aliases, suggestions, spellcheck, synonyms, or GEO fields. - Use bundle tag 9.1.4 (Valkey 9.1.3, valkey-search 1.2.1). The 8.1 and 9.0 bundles ship valkey-search 1.0.3, which has no full-text search and no
FT.AGGREGATE.
Scope and review date: November 2026. This post covers self-managed Redis Stack 7.2 and 7.4, and Redis 8 with the search, JSON, and probabilistic modules, moving to valkey-bundle 9.1.4. Versions, type names, and error strings were checked against Docker Hub, release notes, and the module source code on 10 November 2026. The commands were not run in a lab, so rehearse them on staging.
What carries over from Redis Stack to valkey-bundle?
Redis Stack 7.2.0-v20 bundles Redis 7.2.12 with RediSearch 2.8.28, RedisJSON 2.6.15, RedisTimeSeries 1.10.17, and RedisBloom 2.6.24 (release notes). valkey-bundle 9.1.4 bundles Valkey 9.1.3 with valkey-search 1.2.1, valkey-json 1.0.3, valkey-bloom 1.0.1, and valkey-ldap 1.1.1, per the bundle's versions.json.
The Valkey modules are separate implementations, not forks, and each copies the Redis command surface to a different degree.
Redis Stack modules and their Valkey counterparts
Switch panels to see which feature has a Valkey module and how its data is stored
Redis Stack 7.2
| Feature | Redis Stack 7.2.0-v20 |
|---|---|
| Search and query | RediSearch 2.8.28 |
| JSON documents | RedisJSON 2.6.15 |
| Probabilistic types | RedisBloom 2.6.24: Bloom, cuckoo, Count-Min, Top-K, t-digest |
| Time series | RedisTimeSeries 1.10.17 |
| Graph | Removed in Redis Stack 7.2 |
| JSON type in RDB | ReJSON-RL, encoding 3 |
| Bloom type in RDB | MBbloom-- |
| Index definitions in RDB | ft_index0 auxiliary data |
valkey-bundle 9.1.4
| Feature | valkey-bundle 9.1.4 |
|---|---|
| Search and query | valkey-search 1.2.1 |
| JSON documents | valkey-json 1.0.3 |
| Probabilistic types | valkey-bloom 1.0.1: Bloom filters only |
| Time series | No module |
| Graph | No module |
| JSON type in RDB | ReJSON-RL, loads encoding 3 |
| Bloom type in RDB | bloomfltr |
| Index definitions in RDB | Vk-Search auxiliary data |
Rule of thumb: only JSON values share a storage format. Bloom filters are re-inserted, search indexes are rebuilt, and time series data needs a different home.
Time series and graph data have no Valkey path. Neither the valkey-bundle image nor the valkey-io organization has such a module as of November 2026, and graph already left Redis Stack in 7.2.0-v0. Keep TS.* workloads on Redis or move them to a time series database.
Which valkey-bundle tag gives you which module versions?
Bundle tags do not match server versions: tag 9.1.4 runs Valkey 9.1.3. The GitHub releases page still shows 9.0.1 as the latest, so read versions.json and the Docker Hub tags instead. This table comes from the versions.json history, with each tag's last push date.
| Bundle tag | Last pushed | Valkey | valkey-search | valkey-json | valkey-bloom |
|---|---|---|---|---|---|
| 8.1.11 | 27 Oct 2026 | 8.1.11 | 1.0.3 | 1.0.3 | 1.0.1 |
| 9.0.7 | 27 Oct 2026 | 9.0.7 | 1.0.3 | 1.0.3 | 1.0.1 |
| 9.1.0 | 27 May 2026 | 9.1.0 | 1.2.0 | 1.0.2 | 1.0.1 |
| 9.1.1 | 9 Jul 2026 | 9.1.0 | 1.2.1 | 1.0.2 | 1.0.1 |
| 9.1.2 | 26 Jul 2026 | 9.1.1 | 1.2.1 | 1.0.2 | 1.0.1 |
| 9.1.3 | 27 Sep 2026 | 9.1.2 | 1.2.1 | 1.0.3 | 1.0.1 |
9.1.4 (latest) | 27 Oct 2026 | 9.1.3 | 1.2.1 | 1.0.3 | 1.0.1 |
| 9.2.0-rc4 | 5 Nov 2026 | 9.2.0-rc2 | 1.3.0-rc2 | 1.0.3 | 1.0.1 |
Per the valkey-search release notes, search 1.0 needs Valkey 8.1.1 or later, 1.1 and 1.2 need 9.0.1, and the 1.3 release candidates need 9.1.0. So the 8.1 and 9.0 bundles carry search 1.0.3, which predates full-text search (1.2.0) and FT.AGGREGATE (1.1.0) and needs a vector field in every index. Bundle tags 9.1.0 to 9.1.3 run Valkey 9.1.0 to 9.1.2, while Valkey 9.1.3 is a security release that also fixes a listpack incompatibility with 9.0. Pin 9.1.4.
docker pull valkey/valkey-bundle:9.1.4
docker run -d --name vb -p 6379:6379 valkey/valkey-bundle:9.1.4
docker exec vb valkey-cli INFO server | grep valkey_version
docker exec vb valkey-cli INFO modulesInterpretation: valkey_version should read 9.1.3, and INFO modules lists bf, search, json, and ldap. Pin the full tag; latest and 9.1 move with every patch.
Can valkey-bundle load a Redis Stack RDB file?
No. Three separate checks stop it.
- The file version. Redis 7.4 and later, including Redis Stack 7.4 and Redis 8, write RDB 12 or newer, which the Valkey migration guide calls "not compatible with Valkey".
- Search definitions. RediSearch 2.8 and 2.10 store their index definitions as auxiliary data under the module type
ft_index0, and write it whenever the module is loaded, even with no indexes (spec.c). valkey-search registersVk-Searchinstead. Valkey 9.1.3's rdb.c logs the message quoted in the introduction and callsexit(1)on auxiliary data for an unknown module. - Module value types. A key of type
MBbloom--,MBbloomCF,CMSk-TYPE,TopK-TYPE,TDIS-TYPE, orTSDB-TYPEfails withno matching module type, because no Valkey module registers those names.
# Which RDB version does the source write? 9 bytes: magic plus version.
head -c 9 /data/dump.rdb; echo
# REDIS0011 = Redis 7.2 / Redis Stack 7.2. REDIS0012 or higher = Redis 7.4+.
# Which module types hold data? Run against a replica; one round trip per key.
redis-cli --scan --count 1000 | while read -r k; do redis-cli TYPE "$k"; done \
| sort | uniq -c | sort -rnInterpretation: the second command counts keys per type, such as hash, ReJSON-RL, or MBbloom--. That is your migration inventory: every module type except ReJSON-RL needs its own plan.
A Valkey replica of a Redis Stack primary loads the primary's snapshot during the full sync, through the same code. With RediSearch loaded on the primary, the replica exits. The REPLICAOF method in the Valkey migration guide works for Redis OSS up to 7.2, not for Redis Stack.
What changes for JSON documents on valkey-json?
valkey-json 1.0.3 registers the data type ReJSON-RL with encoding version 3 (json.cc), the same name and version that RedisJSON 2.4 through 8.6 write. In theory that lets a JSON value move as a DUMP payload. RedisJSON 8.8.0 and later write encoding version 4 (lib.rs). valkey-json refuses that with Cannot load document type version 4, because current module's document version is 3.
In practice only Redis Stack 7.2 sources can use DUMP, RESTORE, or MIGRATE for JSON keys. Their payloads carry RDB version 11. Valkey's default rdb-version-check strict rejects payloads from Redis 7.4 and later with DUMP payload version or checksum are wrong. For any other source, read and write the documents as text:
# Copy JSON documents and their TTLs from Redis Stack to valkey-bundle.
# The legacy root path "." returns the bare document in both modules.
import redis # redis-py speaks to both servers
src = redis.Redis(host="redis-stack.internal", port=6379)
dst = redis.Redis(host="valkey-bundle.internal", port=6379)
for key in src.scan_iter(match="product:*", count=1000):
if src.type(key) != b"ReJSON-RL":
continue
doc = src.execute_command("JSON.GET", key, ".")
ttl = src.pttl(key)
pipe = dst.pipeline(transaction=False)
pipe.execute_command("JSON.SET", key, ".", doc)
if ttl > 0:
pipe.pexpire(key, ttl)
pipe.execute()Interpretation: the copy is not atomic, so a document changed after it is read stays stale on Valkey. Run it under dual writes or a write freeze, both covered below.
The command surface is close. valkey-json 1.0.3 registers 23 commands, including JSON.MSET, JSON.RESP, and JSON.TOGGLE. JSON.MERGE is not one of them. The valkey-json documentation lists it, but its command file exists only on the unstable branch. Replace merges with path writes:
# Redis Stack (RedisJSON 2.6): merge a patch into the document
JSON.MERGE product:1001 $ '{"price":18,"stock":{"eu":4}}'
# valkey-json 1.0.3: no JSON.MERGE; write each path instead
JSON.SET product:1001 $.price 18
JSON.SET product:1001 $.stock.eu 4Interpretation: a merge creates missing parent objects, while a path write may not, so test paths whose parents can be absent. valkey-json also caps nesting depth at 128 by default (json.max-path-limit).
How do you move Bloom filters, and what about cuckoo, Count-Min, and Top-K?
valkey-bloom stores filters as its own type, bloomfltr, and implements the common BF.* commands plus its own BF.LOAD (valkey-bloom README). RedisBloom's BF.SCANDUMP and BF.LOADCHUNK have no counterpart, so an existing filter cannot be transferred. A filter cannot list its members either, so the only rebuild is to re-add the original items. If they are gone, start an empty filter and dual-write until it covers the window your application needs.
# On Valkey: create the filter with the error rate and capacity
# your application uses, then re-add the source items in batches
BF.RESERVE seen:emails 0.001 10000000
BF.MADD seen:emails a@example.com b@example.com c@example.com
# Compare with the source filter
BF.INFO seen:emailsInterpretation: RedisBloom's BF.INFO does not report the error rate, so take it from your application's code. valkey-bloom's reply adds error rate, tightening ratio, and max scaled capacity, so parse it by field name. The Bloom filter documentation sets a 128 MB default cap per filter (bf.bloom-memory-usage-limit); raise it before loading larger filters.
Cuckoo filters (CF.*), Count-Min sketches (CMS.*), Top-K (TOPK.*), and t-digest (TDIGEST.*) have no Valkey module. A cuckoo filter that never deletes items can usually become a Bloom filter. The others need a rewrite or a different store.
Which RediSearch commands and features does valkey-search 1.2 support?
valkey-search's COMPATIBILITY.md sets the contract: 1.2 targets RediSearch 2 and 1.3 targets Redis 8, for Dialect 2 queries only. A feature it does not implement returns an error, which the project does not count as a bug.
| Area | RediSearch 2.8 | valkey-search 1.2.1 |
|---|---|---|
| Index and query commands | FT.CREATE, FT.DROPINDEX, FT.INFO, FT._LIST, FT.SEARCH, FT.AGGREGATE | Same six |
| Cursors | FT.CURSOR READ and DEL | Not in 1.2; in 1.3 release candidates |
| Schema changes and aliases | FT.ALTER, FT.ALIASADD, FT.ALIASUPDATE, FT.ALIASDEL | Not available |
| Autocomplete | FT.SUGADD, FT.SUGGET, FT.SUGDEL, FT.SUGLEN | Not available |
| Spellcheck, dictionaries, synonyms | FT.SPELLCHECK, FT.DICT*, FT.SYN* | Not available |
| Diagnostics | FT.EXPLAIN, FT.EXPLAINCLI, FT.PROFILE, FT.TAGVALS | Not available |
| Field types | TEXT, TAG, NUMERIC, VECTOR, GEO, GEOSHAPE | TEXT, TAG, NUMERIC, VECTOR |
| Settings | FT.CONFIG GET and SET | CONFIG GET and SET on search.* |
The RediSearch list comes from its 2.8 commands.json, and the Valkey list from the valkey-search 1.2.1 source and the FT.CREATE reference. Missing aliases break the common reindex pattern that swaps an alias between two indexes.
# Find what the application really calls before you decide.
# Run on a Redis replica; MONITOR is expensive, keep the window short.
timeout 60 redis-cli MONITOR \
| grep -oiE '"(FT|JSON|BF|CF|CMS|TOPK|TDIGEST|TS)\.[A-Z_]+' \
| tr '[:lower:]' '[:upper:]' | sort | uniq -c | sort -rnInterpretation: any command the table marks "Not available", or outside FT, JSON, and BF, needs a code change. Grep the source code too, because a one-minute sample misses nightly jobs.
Which application queries and tools need changes?
COMPATIBILITY.md lists nine migration steps. These four touch application code most often.
- Settings. Replace
FT.CONFIGcalls withCONFIG GETandCONFIG SETonsearch.*names, which differ from RediSearch's. - FT.INFO and INFO parsing. The reply shape and metric names differ, and a silent parse mismatch gives misleading values. Retest dashboards and alerts.
- Unsorted results with LIMIT. Without
SORTBYor a scoring query, order is undefined, so a page of 20 can hold different rows. - Errors and ACLs. Error text may differ, so do not match on it. Valkey enforces ACL key patterns on
FT.SEARCHandFT.AGGREGATE; RediSearch does not.
# Before (Redis Stack): module settings and an unsorted, paginated query
FT.CONFIG GET *
FT.SEARCH idx:product "@tags:{sale}" LIMIT 0 20
# After (valkey-bundle): native config and a deterministic order
CONFIG GET search.*
FT.SEARCH idx:product "@tags:{sale}" SORTBY price ASC LIMIT 0 20 DIALECT 2Interpretation: valkey-search does not need SORTABLE for SORTBY, per the FT.CREATE reference, and an explicit DIALECT 2 keeps the query inside the compatibility contract. Run the new form on Redis Stack first to compare like with like. Also expect Index does not support offsets for quoted phrases on NOOFFSETS indexes, and fix parsers that read attributes by position.
Should you dual-write, re-ingest, or copy the data?
All three paths end with data on Valkey, indexes rebuilt, and reads switched. They differ in the data source and whether writes pause.
Moving a Redis Stack workload to valkey-bundle
Data moves by copy or re-ingest, indexes build on Valkey, and reads switch last
Before step 3: compare key counts per type and run your top queries with SORTBY on both sides. Redis Stack stays untouched until then, so it is your rollback.
| Path | How it works | Fits when | Watch for |
|---|---|---|---|
| Re-ingest | Replay from your primary database or event log | Valkey holds derived data: a cache or search projection | Load on the source; the only full rebuild for Bloom filters |
| Dual-write | Write to both stores, backfill old data, switch reads | Writes cannot pause | A failed second write leaves the stores apart |
| Logical copy | Scan Redis Stack, write each key with type-aware commands | Redis Stack is the only copy | Needs a write freeze or dual writes; carry TTLs |
For core types, copy like the JSON script: HGETALL and HSET for hashes, and so on. From Redis Stack 7.2 only, MIGRATE ... COPY KEYS also works for core types and JSON keys, because their payloads carry RDB version 11. It returns an error on any Bloom, cuckoo, or time series key, so leave those out of the key list.
How do you rebuild the search indexes on Valkey?
Rerun each index definition on valkey-bundle, ideally before loading data. The search documentation says keys written after an index exists are indexed on arrival, while existing keys wait for a background backfill that can be slow on a large keyspace.
# Export the schema from Redis Stack (RediSearch 2.8)
redis-cli FT._LIST
redis-cli FT.INFO idx:product # read index_definition and attributes
# Recreate it on valkey-bundle: JSON source, three fields
valkey-cli FT.CREATE idx:product ON JSON PREFIX 1 product: SCHEMA \
$.name AS name TEXT $.price AS price NUMERIC $.tags AS tags TAGInterpretation: FT.INFO on Redis Stack shows the prefixes, field paths, and options to copy. Fold any FT.ALTER history into the final schema and drop GEO and GEOSHAPE fields. In the valkey-search 1.2.1 parser, FILTER, SCORE_FIELD, PAYLOAD_FIELD, and LANGUAGE_FIELD fail with an error such as The parameter `FILTER` is not supported, LANGUAGE accepts only ENGLISH, and SORTABLE is accepted and ignored.
Checking modules and backfill on valkey-bundle
Illustrative output: field names follow the FT.INFO reference, values are examples
Done means: state reads ready and num_docs matches the source index. The backfill is node-local, so check each replica as well, per the FT.INFO reference.
In cluster mode, valkey-search nodes talk over gRPC on the Valkey port plus 20294 (26673 for the default port). Open it between nodes before you create indexes; Redis Stack has no equivalent, so it is easy to miss.
What does the cutover runbook look like?
This runbook assumes a logical copy with a short write freeze. With dual writes or re-ingest, steps 6 to 8 need no freeze.
Redis Stack to valkey-bundle cutover
Nine steps; steps 6 to 8 are the write-freeze window when you copy instead of dual-writing
-
Inventory module data and commands
Count keys per type and sample the FT, JSON, BF, CF, and TS commands the application sends.
redis-cli MODULE LIST redis-cli FT._LIST -
Decide each unsupported feature
Time series, graph, cuckoo, Count-Min, Top-K, t-digest, aliases, suggestions, GEO fields, and
JSON.MERGEeach need a code change or another home. -
Start valkey-bundle 9.1.4 with persistence
Pin the tag. Pass server flags through
VALKEY_EXTRA_FLAGS.docker run -d --name vb -p 6379:6379 \ -e VALKEY_EXTRA_FLAGS='--appendonly yes' \ valkey/valkey-bundle:9.1.4 -
Create indexes before loading data
Keys written after
FT.CREATEare indexed on arrival, so no long backfill follows the copy. In cluster mode, open port 26673 first.valkey-cli FT.CREATE idx:product ON JSON \ PREFIX 1 product: SCHEMA $.price AS price NUMERIC -
Bulk copy or re-ingest
Copy JSON and core keys, rebuild Bloom filters from source items, and carry TTLs.
-
Freeze writes and run a final pass
Write freeze startsStop writers and copy keys changed since the bulk pass, or repeat the full copy.
-
Verify counts and queries
Write freezeCompare key counts per type and
num_docsper index. Diff your top queries withSORTBY.valkey-cli FT.INFO idx:product valkey-cli DBSIZE -
Switch the application
Write freeze endsRepoint reads and writes to valkey-bundle and watch error rates on FT and JSON calls.
-
Keep Redis Stack as a fallback
Leave it running read-only for an agreed period, then decommission it.
Rollback point: until step 8, Redis Stack holds every write. After it, going back means copying writes made on Valkey back to Redis Stack, so keep the rollback window short or dual-write in reverse.
valkey-search 1.3 is still a release candidate as of November 2026. Its RediSearch compatibility fixes are off by default behind search.emulate-release, so plan this migration on 1.2.1.
Frequently asked questions
Can I load a Redis Stack dump.rdb into valkey-bundle?
No. Redis Stack 7.4 and Redis 8 write RDB version 12 or newer, which Valkey's migration guide calls incompatible. Any Redis Stack file written with RediSearch loaded also carries ft_index0 auxiliary data, and Valkey exits on data for a module it lacks. Move the data logically or re-ingest it.
Is valkey-json compatible with RedisJSON?
Mostly. valkey-json 1.0.3 uses the RedisJSON type name ReJSON-RL with encoding version 3 and implements 23 JSON commands. JSON.MERGE is missing from 1.0.3, which every current valkey-bundle tag ships. RedisJSON 8.8 and later write encoding version 4, which valkey-json cannot load. Test your JSONPath queries on staging.
Does Valkey have RedisTimeSeries or RedisGraph equivalents?
No. As of November 2026, valkey-bundle ships search, JSON, Bloom, and LDAP modules only, and the valkey-io project publishes no time series or graph module. RedisGraph left Redis Stack in 7.2. Keep time series workloads on Redis or move them to a time series database.
Do I have to rebuild RediSearch indexes when moving to Valkey?
Yes. valkey-search's compatibility document says RediSearch RDB files cannot be loaded and indexes must be rebuilt from the underlying hashes or JSON documents. Create each index with FT.CREATE on Valkey, ideally before loading data, then watch FT.INFO until the state reads ready on every node.
Which valkey-bundle tag should I use for a Redis Stack migration?
Use 9.1.4, pinned. It runs Valkey 9.1.3 with valkey-search 1.2.1, valkey-json 1.0.3, and valkey-bloom 1.0.1. The 8.1 and 9.0 bundles ship valkey-search 1.0.3, which lacks full-text search and FT.AGGREGATE. Bundle tags 9.1.0 to 9.1.3 run older 9.1 patches.
Key takeaways
- Plan a logical move: Redis Stack snapshots and replication streams do not load into valkey-bundle.
- JSON documents carry over as text with few command changes; replace
JSON.MERGE. - Rebuild Bloom filters from source items, and find a new home for time series, cuckoo, Count-Min, Top-K, and t-digest data.
- Recreate every index with
FT.CREATE, removeFT.CONFIG, alias, and GEO usage, and addSORTBYandDIALECT 2to paginated queries. - Pin valkey-bundle 9.1.4, open port 26673 in cluster mode, and keep Redis Stack as the rollback until counts and queries match.
Plan your Redis Stack migration with JusDB
JusDB's Valkey migration team can review your Redis Stack module usage, map each FT, JSON, and BF call to valkey-bundle, and write a cutover runbook with a tested rollback path.
Bring your Redis Stack version, module list, key counts per type, index definitions, and the commands your services send. Your team approves every production change. For the wider choice between the two projects, see our Redis vs Valkey comparison.