Valkey: Search and JSON
Store and query JSON documents with the Valkey search module
👋 Welcome to the Stackhero documentation!
Stackhero offers a ready-to-use Valkey cloud solution that provides a host of benefits, including:
Valkey Adminweb UI included.- Unlimited message size and transfers.
- Effortless updates with just a click.
- Optimal performance and robust security powered by a private, dedicated infrastructure.
Save time and simplify your life: it only takes 5 minutes to try Stackhero's Valkey cloud hosting solution!
Your Valkey instance on Stackhero includes essential modules maintained by the Valkey project. These modules make Valkey much more than a cache: you can store native JSON documents, index your data, and run tag, numeric, text, and vector queries, all without managing a separate database.
Three modules are available, each included in your plan and licensed under the same permissive BSD 3-Clause license as Valkey:
- JSON (
JSON.*commands): Store and update structured JSON documents with JSONPath support. You can read or modify individual fields directly, so you never need to rewrite the full document for small changes. - Search (
FT.*commands): Run secondary indexing, tag, numeric, and full-text queries, plus vector similarity search. - Bloom (
BF.*commands): Use Bloom filters to efficiently answer "have I already seen this?" across large datasets, using minimal memory.
Enabling the modules
Modules are off by default, so your existing service keeps its current behavior until you enable them.
- Open your service on the Stackhero dashboard.
- Go to the service configuration.
- In the Modules section, select the modules you want to enable.
- Save your changes.
Valkey restarts to load the selected modules. This usually takes only a few seconds.
If you have stored data using a module (such as a JSON document or a Bloom filter), keep that module enabled. Valkey cannot read that data without the module that created it. Disabling the module would prevent your service from restarting successfully.
You can check which modules are currently loaded at any time:
valkey-cli -u "rediss://default:<yourPassword>@<XXXXXX>.stackhero-network.com:<PORT_TLS>" MODULE LIST
Storing JSON documents
You can store structured documents natively as JSON, without serializing them into strings:
JSON.SET product:1 $ '{"name":"Espresso machine","brand":"Bianca","price":459,"stock":12}'
Reading or updating a single field is fast, atomic, and handled server-side:
JSON.GET product:1 $.price
# "[459]"
JSON.NUMINCRBY product:1 $.stock -1
# "[11]"
This approach removes the need to fetch and parse the entire document in your application for every update. For example, decrementing a stock counter is now a single atomic operation. There are no more race conditions or extra code.
The JSON.* command set matches the API of RedisJSON, so most Valkey and Redis clients work without changes.
Indexing and searching
Create an index once, and Valkey keeps it up to date for every key matching your prefix, even for keys written before the index was created:
FT.CREATE productsIndex
ON HASH
PREFIX 1 product:
SCHEMA
name TEXT
brand TAG
price NUMERIC
You can query your indexed data with expressive search commands:
# Exact tag match
FT.SEARCH productsIndex "@brand:{Bianca}"
# Numeric range
FT.SEARCH productsIndex "@price:[0 500]"
# Combined query
FT.SEARCH productsIndex "@brand:{Bianca} @price:[0 500]"
# Full-text search by name
FT.SEARCH productsIndex "espresso"
You can also run aggregations on the same index with FT.AGGREGATE. The FT.INFO command lets you check index status, including the progress of background indexing jobs.
JSON documents are indexable, too. When the JSON module is enabled, you can use ON JSON and JSONPath expressions in your schema.
Example: Using Valkey search in Node.js
Because Valkey uses the same protocol as Redis, any Redis client is compatible. You can use this example with the official node-redis client:
import { createClient, SCHEMA_FIELD_TYPE } from 'redis';
const client = createClient({ url: process.env.STACKHERO_VALKEY_URL_TLS });
await client.connect();
// Create the index once at startup
try {
await client.ft.create(
'productsIndex',
{
name: SCHEMA_FIELD_TYPE.TEXT,
brand: SCHEMA_FIELD_TYPE.TAG,
price: SCHEMA_FIELD_TYPE.NUMERIC
},
{ ON: 'HASH', PREFIX: 'product:' }
);
} catch (error) {
if (!error.message.includes('Index already exists')) {
throw error;
}
}
await client.hSet('product:1', { name: 'Espresso machine', brand: 'Bianca', price: '459' });
const results = await client.ft.search('productsIndex', '@brand:{Bianca} @price:[0 500]');
console.log(results.total, results.documents);
await client.quit();
Example: Using Valkey search in Python
You can use the redis-py client to interact with Valkey search features:
import os
import redis
from redis.commands.search.field import TextField, TagField, NumericField
from redis.commands.search.index_definition import IndexDefinition, IndexType
from redis.commands.search.query import Query
r = redis.from_url(os.environ['STACKHERO_VALKEY_URL_TLS'], decode_responses=True)
# Create the index once at startup
try:
r.ft('productsIndex').create_index(
(TextField('name'), TagField('brand'), NumericField('price')),
definition=IndexDefinition(prefix=['product:'], index_type=IndexType.HASH),
)
except redis.ResponseError as error:
if 'Index already exists' not in str(error):
raise
r.hset('product:1', mapping={'name': 'Espresso machine', 'brand': 'Bianca', 'price': 459})
results = r.ft('productsIndex').search(Query('@brand:{Bianca} @price:[0 500]'))
print(results.total, results.docs)
Good to know
- The search module offers a focused set of commands:
FT.CREATE,FT.SEARCH,FT.AGGREGATE,FT.INFO,FT.DROPINDEX, andFT._LIST. These cover tag, numeric, text, and vector queries efficiently. If your application needs advanced full-text features (such as spell checking, synonyms, or suggestion dictionaries), the Redis query engine provides more depth. - Indexes are per-database and work in every database. For example, an index created in database 3 is only visible and queryable from database 3. This is a capability where Valkey extends beyond Redis database selection, which only supports indexing on database 0.
- Indexes use your plan's memory, just like your data. You can monitor
used_memoryin your Prometheus metrics after building an index. - Indexing existing keys runs in the background. Immediately after running
FT.CREATE, search results might be incomplete for a few seconds while the index is being built. - All module commands are enabled. Every command from every module is available on your service, with no restrictions.
If you want to explore vector similarity, semantic search, or retrieval-augmented generation, you can read the vector search guide.