JusDB
Free DB Audit
NoSQL Databases

Moving Off Redis Stack: What Carries Over to valkey-search, valkey-json, and valkey-bloom

See what carries over from Redis Stack to valkey-bundle 9.1: which JSON, Bloom, and search data moves, which indexes you rebuild, which commands change, and how to cut over.

JusDB Team
Published November 9, 2026
Updated November 10, 2026
18 min read

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.

TL;DR
  • 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_index0 data 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.MERGE is 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 no FT.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

FeatureRedis Stack 7.2.0-v20
Search and queryRediSearch 2.8.28
JSON documentsRedisJSON 2.6.15
Probabilistic typesRedisBloom 2.6.24: Bloom, cuckoo, Count-Min, Top-K, t-digest
Time seriesRedisTimeSeries 1.10.17
GraphRemoved in Redis Stack 7.2
JSON type in RDBReJSON-RL, encoding 3
Bloom type in RDBMBbloom--
Index definitions in RDBft_index0 auxiliary data

valkey-bundle 9.1.4

Featurevalkey-bundle 9.1.4
Search and queryvalkey-search 1.2.1
JSON documentsvalkey-json 1.0.3
Probabilistic typesvalkey-bloom 1.0.1: Bloom filters only
Time seriesNo module
GraphNo module
JSON type in RDBReJSON-RL, loads encoding 3
Bloom type in RDBbloomfltr
Index definitions in RDBVk-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 tagLast pushedValkeyvalkey-searchvalkey-jsonvalkey-bloom
8.1.1127 Oct 20268.1.111.0.31.0.31.0.1
9.0.727 Oct 20269.0.71.0.31.0.31.0.1
9.1.027 May 20269.1.01.2.01.0.21.0.1
9.1.19 Jul 20269.1.01.2.11.0.21.0.1
9.1.226 Jul 20269.1.11.2.11.0.21.0.1
9.1.327 Sep 20269.1.21.2.11.0.31.0.1
9.1.4 (latest)27 Oct 20269.1.31.2.11.0.31.0.1
9.2.0-rc45 Nov 20269.2.0-rc21.3.0-rc21.0.31.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.

bash
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 modules

Interpretation: 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 registers Vk-Search instead. Valkey 9.1.3's rdb.c logs the message quoted in the introduction and calls exit(1) on auxiliary data for an unknown module.
  • Module value types. A key of type MBbloom--, MBbloomCF, CMSk-TYPE, TopK-TYPE, TDIS-TYPE, or TSDB-TYPE fails with no matching module type, because no Valkey module registers those names.
bash
# 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 -rn

Interpretation: 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.

Replication fails the same way

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:

python
# 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:

bash
# 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 4

Interpretation: 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.

bash
# 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:emails

Interpretation: 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.

AreaRediSearch 2.8valkey-search 1.2.1
Index and query commandsFT.CREATE, FT.DROPINDEX, FT.INFO, FT._LIST, FT.SEARCH, FT.AGGREGATESame six
CursorsFT.CURSOR READ and DELNot in 1.2; in 1.3 release candidates
Schema changes and aliasesFT.ALTER, FT.ALIASADD, FT.ALIASUPDATE, FT.ALIASDELNot available
AutocompleteFT.SUGADD, FT.SUGGET, FT.SUGDEL, FT.SUGLENNot available
Spellcheck, dictionaries, synonymsFT.SPELLCHECK, FT.DICT*, FT.SYN*Not available
DiagnosticsFT.EXPLAIN, FT.EXPLAINCLI, FT.PROFILE, FT.TAGVALSNot available
Field typesTEXT, TAG, NUMERIC, VECTOR, GEO, GEOSHAPETEXT, TAG, NUMERIC, VECTOR
SettingsFT.CONFIG GET and SETCONFIG 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.

bash
# 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 -rn

Interpretation: 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.CONFIG calls with CONFIG GET and CONFIG SET on search.* 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 SORTBY or 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.SEARCH and FT.AGGREGATE; RediSearch does not.
bash
# 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 2

Interpretation: 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

Redis Stack to valkey-bundle migration path Step 1: the application keeps reading and writing Redis Stack. Step 2: data reaches valkey-bundle by a logical copy from Redis Stack or by re-ingesting it from the source of truth, and valkey-search builds the indexes created with FT.CREATE. Step 3: after counts and query results match, the application switches its reads and writes to valkey-bundle, and Redis Stack is retired. Application reads and writes Redis Stack current store valkey-bundle 9.1.4 1 2 copy or re-ingest, FT.CREATE builds indexes 3 switch reads and writes once counts and query results match

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.

PathHow it worksFits whenWatch for
Re-ingestReplay from your primary database or event logValkey holds derived data: a cache or search projectionLoad on the source; the only full rebuild for Bloom filters
Dual-writeWrite to both stores, backfill old data, switch readsWrites cannot pauseA failed second write leaves the stores apart
Logical copyScan Redis Stack, write each key with type-aware commandsRedis Stack is the only copyNeeds 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.

bash
# 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 TAG

Interpretation: 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

valkey@vb-01:~
$ valkey-cli INFO modules | cut -d, -f1# Modulesmodule:name=bfmodule:name=searchmodule:name=jsonmodule:name=ldap$ valkey-cli FT.INFO idx:productindex_name idx:productnum_docs 412880hash_indexing_failures 0backfill_in_progress 1backfill_complete_percent 0.63mutation_queue_size 0state backfill_in_progress

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

  1. 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
  2. Decide each unsupported feature

    Time series, graph, cuckoo, Count-Min, Top-K, t-digest, aliases, suggestions, GEO fields, and JSON.MERGE each need a code change or another home.

  3. 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
  4. Create indexes before loading data

    Keys written after FT.CREATE are 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
  5. Bulk copy or re-ingest

    Copy JSON and core keys, rebuild Bloom filters from source items, and carry TTLs.

  6. Freeze writes and run a final pass

    Write freeze starts

    Stop writers and copy keys changed since the bulk pass, or repeat the full copy.

  7. Verify counts and queries

    Write freeze

    Compare key counts per type and num_docs per index. Diff your top queries with SORTBY.

    valkey-cli FT.INFO idx:product valkey-cli DBSIZE
  8. Switch the application

    Write freeze ends

    Repoint reads and writes to valkey-bundle and watch error rates on FT and JSON calls.

  9. 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, remove FT.CONFIG, alias, and GEO usage, and add SORTBY and DIALECT 2 to 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.

Share this article

Database engineering notes

Articles like this one, in your inbox. No spam, unsubscribe anytime.

JusDB Team

Official JusDB content team

Keep reading

Moving a Multi-Database Valkey Instance into a 9.x Cluster

Move a Valkey instance that uses SELECT 1 to 15 into a 9.x cluster: keep or remap databases, copy each one, verify counts per database, and keep a way back.

Redis18 minNov 10, 2026
Read

Valkey Keyspace Notifications in Production: Expired Events, hexpired and Cluster Mode

Run Valkey keyspace notifications in production: why expired and hexpired events lag the TTL, how to subscribe on every cluster node, and when a stream is safer.

Redis20 minNov 10, 2026
Read

Valkey GLIDE in Production: AZ-Affinity Reads and Migrating from Legacy Clients

Configure Valkey GLIDE AZ-affinity reads on servers and clients, learn what GLIDE 2.5.3 does not support, and migrate from redis-py, Jedis, ioredis, or go-redis one service at a time.

Redis20 minNov 10, 2026
Read