JSONPath access instead of full serialization
Anyone who has stored JSON data as a plain string in Redis knows the problem: even the smallest change to a single field requires loading the entire document, deserializing it, changing it, and writing the whole thing back. RedisJSON solves this by managing JSON documents as their own native data type and allowing targeted access to individual paths through JSONPath expressions, without ever moving the whole document.
Table of Contents
- 1. The Problem with String-Based JSON in Redis
- 2. RedisJSON as Its Own Data Type in Redis Stack
- 3. JSONPath: Targeted Reads Without Loading the Whole Document
- 4. Atomic Partial Updates Instead of Read-Modify-Write
- 5. Performance Compared to String-Based JSON
- 6. Practical Example: Storing Product Configuration Data
- 7. Combining with RediSearch: Indexed Queries over JSON Documents
- 8. Persistence and Memory Usage of JSON Documents
- 9. Client Integration in PHP and Magento Environments
- 10. Summary
- 11. FAQ
1. The Problem with String-Based JSON in Redis
Without RedisJSON, Redis offers exactly one way to store a JSON document: as a serialized string via SET and GET. To Redis itself the content is meaningless, it is simply a byte sequence. Any application that wants to read or change even a single field of a document has to transfer the entire string, deserialize it on the client, apply the desired change, and write the whole document back serialized again.
For small documents this detour barely matters, but for larger, nested structures, such as product configurations with hundreds of attributes and variants, the overhead adds up noticeably. There is also a race condition risk: two parallel processes that read, modify, and write back the same document overwrite each other unless the operation is additionally protected with WATCH, MULTI, and EXEC or a Lua script against concurrent writes.
2. RedisJSON as Its Own Data Type in Redis Stack
RedisJSON is a module that has been a fixed part of the Redis Stack default package for some time and is also available in Redis Enterprise and with most managed Redis providers. It introduces a new data type that represents JSON documents internally as a tree of values, similar to what document databases do, only within the familiar Redis infrastructure with its usual latency and persistence model.
The key difference from string-based JSON already shows when creating a document: JSON.SET expects not only the key but also a JSONPath at which the document or a subsection of it is written. Addressing the whole document with the path $ still works like a classic SET, but from here the real strength of the module opens up: targeted access to individual nodes of the tree.
redis-cli JSON.SET product:4711 $ '{"sku":"SHIRT-BLUE-M","name":"Basic Shirt Blue","price":29.90,"stock":{"total":140,"reserved":12},"variants":["S","M","L","XL"]}'
redis-cli JSON.GET product:4711 $.price
# [29.9]
redis-cli JSON.TYPE product:4711 $.variants
# ["array"]
3. JSONPath: Targeted Reads Without Loading the Whole Document
JSONPath expressions make it possible to request exactly the part of a document that is actually needed. Instead of loading product:4711 in full just to check the reserved stock, JSON.GET product:4711 $.stock.reserved is enough. For documents with many kilobytes of payload, such as extensive product descriptions with multilingual attributes, this drastically reduces the amount of data transferred and correspondingly lowers network latency between the application and the Redis instance.
RedisJSON supports both the restricted, legacy-compatible path syntax and the full JSONPath with wildcards, filters, and recursive search through the $ notation. This makes it possible to formulate queries such as all variants with stock below a threshold without having to move the filter logic into the application, which noticeably relieves the client side in read-heavy workloads.
redis-cli JSON.GET product:4711 '$.variants[?(@.stock<5)]'
redis-cli JSON.GET product:4711 $.stock.reserved
# [12]
4. Atomic Partial Updates Instead of Read-Modify-Write
The core practical advantage of RedisJSON shows up on writes. Commands like JSON.SET with a specific path, JSON.NUMINCRBY for numeric fields, or JSON.ARRAPPEND for arrays change a targeted subsection of the document, atomically and without the application ever having to load the full document first. Stock can be decremented directly inside the Redis server, without any read-modify-write cycle in application code.
This structurally eliminates the race condition described above, because Redis itself guarantees the atomicity of the path operation. Two parallel order processes that both run JSON.NUMINCRBY product:4711 $.stock.reserved 1 at the same time do not compete with each other. Every call is processed serially in the single-threaded command loop of Redis, so the result is always consistent, without any extra locking in application code.
redis-cli JSON.NUMINCRBY product:4711 $.stock.reserved 1
redis-cli JSON.ARRAPPEND product:4711 $.variants '"XXL"'
redis-cli JSON.GET product:4711 $.stock
# [{"total":140,"reserved":13}]
5. Performance Compared to String-Based JSON
The speed gain of RedisJSON does not come from the module serializing faster than an application would in general, but from the fact that on partial access the full serialization and deserialization is simply skipped. For a ten kilobyte document from which only a single price field is read, string-based JSON always transfers the full ten kilobytes over the network and has to parse them client side, RedisJSON transfers only the few bytes of the requested path.
On writes the effect is even stronger: a string update always requires the entire document as the new value, RedisJSON internally updates only the affected subtree. For very large documents with many kilobytes and frequent small changes, such as constantly updated stock levels in product catalogs with thousands of items, this difference shows up clearly in benchmarks as improved latency and network throughput.
6. Practical Example: Storing Product Configuration Data
A typical use case in e-commerce is product configuration data with nested attributes: base data, price tiers per customer group, variants with their own stock, and metadata for different sales channels. Instead of splitting this structure across several flat Redis keys or caching it as a single JSON string, RedisJSON represents the entire structure as one document that can be read and written per path.
In practice this means a configurator frontend only requests the paths relevant for display when loading, such as price and availability per variant, while a background job that synchronizes stock levels exclusively updates the affected numeric fields with JSON.NUMINCRBY. Both access patterns run independently of each other without blocking or overwriting one another through full document overwrites.
{
"sku": "JACKET-SUMMER-42",
"name": "Lightweight Summer Jacket",
"priceTiers": {
"standard": 89.90,
"reseller": 62.00,
"vip": 74.90
},
"variants": [
{"size": "M", "color": "blue", "stock": 34},
{"size": "L", "color": "blue", "stock": 12}
],
"channels": ["web", "marketplace", "b2b-portal"]
}
7. Combining with RediSearch: Indexed Queries over JSON Documents
RedisJSON often unfolds its full strength only in combination with the RediSearch module, which can build secondary indexes directly on JSON documents. While RedisJSON provides efficient access by key and path, RediSearch allows queries across attributes, such as all products of a category with stock above a threshold, without the application having to iterate over all keys itself.
In many cases this combination does not replace a dedicated search index, but it considerably reduces the need for additional infrastructure for simple, attribute-based filter queries. Anyone already using RedisJSON for data storage who only occasionally needs to filter across a few fields can potentially save a separate Elasticsearch or OpenSearch instance for that part of the application.
8. Persistence and Memory Usage of JSON Documents
RedisJSON documents are backed up like any other Redis data type through the configured persistence strategy, that is, through RDB snapshots, AOF, or a combination of both. To the server, a JSON document is not a special case, it is serialized during a snapshot just like a hash or a sorted set structure, so nothing changes about existing backup and replication processes.
Memory usage deserves a closer look: the internal tree structure of RedisJSON requires additional management overhead per node compared to a raw, compressed JSON string. With a very large number of small, deeply nested documents, the memory footprint can noticeably exceed that of a comparable string-based approach, which should be explicitly accounted for when planning capacity for large product catalogs, for example through MEMORY USAGE sampling on representative keys.
redis-cli MEMORY USAGE product:4711 SAMPLES 0
9. Client Integration in PHP and Magento Environments
For integration with PHP applications, both phpredis, provided it is compiled with RedisJSON support, and Predis via generic command calls offer access to the JSON.* commands. In Magento contexts, RedisJSON is most useful for custom data structures outside the standard cache framework, such as individually built configuration or feature flag stores, and less relevant for the full page cache or session storage that the framework already abstracts.
A common stumbling block in practice: RedisJSON is not part of the standard Redis server, it has to be loaded explicitly as a module, either through Redis Stack or a manually compiled .so file. Anyone planning to use RedisJSON in a production environment should check beforehand whether the managed service or Docker image in use actually ships the module, because a missing module does not produce a helpful error on JSON.SET, it simply results in an unknown command.
redis-cli MODULE LIST
# 1) "name" "ReJSON" "ver" 20602
| Aspect | String-Based JSON | RedisJSON |
|---|---|---|
| Reading a single field | Load the full document and parse it client side | Direct JSONPath access without full deserialization |
| Writing a single field | Read-modify-write cycle needed in application code | Atomic JSON.SET or JSON.NUMINCRBY on the path |
| Race conditions on parallel writes | Only avoidable with WATCH, MULTI, and EXEC or Lua | Structurally excluded through path-level atomicity |
| Network load for large documents | Always the full document size | Only the size of the requested path |
| Availability | In every Redis server without an extra module | Requires Redis Stack or the RedisJSON module |
| Combinability with indexing | Only possible through external indexes | Direct indexing via RediSearch on the same document |
Mironsoft
Cache layer setup and Magento Redis integration
Magento cache that isn't quite working or is misconfigured?
We set up Redis as a cache and session backend for Magento cleanly, tune memory usage and eviction strategies, and make sure full page cache and session storage work together reliably.
Redis Setup
Configure the cache, session, and FPC backend production-ready for Magento.
Memory Tuning
Match memory usage and eviction policies to the shop's actual load.
High Availability Setup
Set up Redis Sentinel or Cluster for resilient Magento environments.
10. Summary
RedisJSON: The Essentials at a Glance
Data Type
Its own JSON document type with a tree structure instead of a serialized string
Core Commands
JSON.SET, JSON.GET, JSON.NUMINCRBY, JSON.ARRAPPEND with JSONPath addressing
Typical Use
Nested configuration data with frequent partial updates, such as product variants
Limits
Extra memory overhead per node, requires Redis Stack or a dedicated module