what actually changes compared to RESP2
Since Redis 6, RESP3 has offered a reworked version of the Redis protocol that supports significantly more structured data types than RESP2, which has been the established standard for decades. For applications that only talk to Redis through a mature client library, much of this stays invisible, but anyone writing custom serialization, wanting to use client-side caching, or simply trying to understand why certain values suddenly come back as a double instead of a string should know the practical differences. This article covers which new data types RESP3 introduces, how client library compatibility looks in practice, and what actually changes during a migration.
Table of Contents
- 1. The baseline: RESP2 as a decades-old standard
- 2. New data types in RESP3: maps, sets, doubles, and more
- 3. Push messages: the decisive structural difference
- 4. Switching protocols via HELLO: how a client enables RESP3
- 5. Client library compatibility: what to watch for in practice
- 6. Practical impact on your own application code
- 7. Rolling out incrementally instead of a big-bang switch
- 8. Backward compatibility: why RESP2 is not going away
- 9. Debugging and diagnosis: identifying a connection's protocol version
- 10. Summary
- 11. FAQ
1. The baseline: RESP2 as a decades-old standard
RESP2, the Redis Serialization Protocol in its second version, has been in use since the earliest Redis versions and only knows a manageable number of basic reply types: simple strings, errors, integers, bulk strings for binary or longer text data, and arrays, which can be nested to express more complex structures such as hash or sorted-set replies. Anything with more semantic structure, such as a mapping from keys to values, gets encoded as a flat array alternating key and value, and the client library itself has to know that a given command's array reply should actually be interpreted as a map.
This simplicity was long an advantage because it made the protocol easy to implement, but it meant the actual data structure of a command's result lived implicitly in the client library's knowledge rather than explicitly in the protocol itself. For new data types like doubles from ZSCORE or genuine boolean values, RESP2 had no dedicated representation; they were encoded as a bulk string or integer and had to be interpreted by the application itself.
2. New data types in RESP3: maps, sets, doubles, and more
RESP3 introduces a range of explicit new types that more precisely capture what a command actually returns. The map type, introduced with %, encodes key-value mappings explicitly as such instead of disguising them as a flat array, so HGETALL under RESP3 returns a genuine map instead of an array. The set type, introduced with ~, does the same for commands like SMEMBERS, whose result is semantically an unordered collection without duplicates.
For numbers with decimal places, RESP3 introduces the double type with the prefix ,, so commands like ZSCORE now return a genuine floating-point value that client libraries can parse directly as a number instead of manually converting a bulk string into one. There is also a boolean type with the prefix #, a big-number type with ( for values exceeding the range of a normal 64-bit integer, and an explicit null type with _ that resolves the previous ambiguity between an empty bulk string and null.
# RESP2: HGETALL returns a flat array
*4
$4
name
$5
Alice
$3
age
$2
30
# RESP3: HGETALL returns a genuine map
%2
$4
name
$5
Alice
$3
age
$2
30
3. Push messages: the decisive structural difference
Perhaps the most important structural difference is the new push type with the prefix >. Push messages are server messages that can arrive over the same connection outside the normal request-response cycle, without the client having previously issued a matching request. This is exactly what the tracking protocol used in client-side caching builds on: invalidation messages arrive as push messages, regardless of whether the client happens to be waiting on a different reply at that moment.
PubSub messages, too, can be delivered as push messages under RESP3 instead of as ordinary array replies, which lets client libraries cleanly separate subscribe messages from ordinary command replies at the protocol level instead of having to distinguish the two by inspecting array contents, as under RESP2. RESP2 simply has no such mechanism, which is why features like tracking-based client-side caching strictly require RESP3.
4. Switching protocols via HELLO: how a client enables RESP3
A Redis connection starts in RESP2 mode by default to stay compatible with older clients. A client wanting to use RESP3 sends the command HELLO 3 after connecting, after which the server responds in RESP3 mode for the remainder of that connection. The HELLO command additionally takes over tasks that used to be handled separately via AUTH and SELECT, so authentication, database selection, and protocol switching can all happen in a single round trip.
It is important that the protocol switch applies per connection, not globally to the server: two connections open at the same time can use different protocol versions, allowing a gradual rollout within an application without having to switch the entire connection pool at once.
# Switch a connection to RESP3, including authentication
redis-cli
> HELLO 3 AUTH myuser mypassword
1# "server" => "redis"
2# "proto" => (integer) 3
3# "id" => (integer) 42
...
# Without HELLO, a connection stays in RESP2 mode
5. Client library compatibility: what to watch for in practice
Not every Redis client library supports RESP3 equally completely. Mature, actively maintained libraries for common languages usually offer an explicit configuration option to enable RESP3, while defaulting to the more broadly compatible RESP2 mode so existing applications are not changed without being asked. Older or less actively maintained libraries sometimes only support RESP2 and, when a HELLO 3 is attempted, either return a protocol error or silently ignore the new types.
For PHP applications with common Redis extensions, support is fairly mature by now, but it is worth explicitly checking before a switch whether the specific library version in use correctly translates RESP3 reply types into the expected PHP data types, particularly for maps, which need to be handled differently from flat arrays, and for doubles, which now arrive as a PHP float instead of a string.
6. Practical impact on your own application code
For applications using a modern client library with full RESP3 support, the switch usually stays invisible: the library transparently translates maps, sets, and doubles into the respective native data types of the programming language, and application code that treats the result of HGETALL as an associative array, for instance, behaves identically under RESP2 and RESP3.
The difference becomes noticeable mainly in code that explicitly checks return types, for instance with is_string() or is_array() in PHP, or in code that builds debug output or logging directly from the raw protocol reply. Anyone who has processed ZSCORE results as strings so far, for example through string concatenation, may encounter a float instead of a string under RESP3, which rarely causes errors in loosely typed languages but can require explicit adjustments in strictly typed code.
{
"zscore_result_resp2": "3.5",
"zscore_result_resp3": 3.5,
"hgetall_result_resp2": ["name", "Alice", "age", "30"],
"hgetall_result_resp3": {"name": "Alice", "age": "30"}
}
7. Rolling out incrementally instead of a big-bang switch
A blanket, immediate switch of the entire application to RESP3 is rarely necessary, since RESP2 remains supported long-term and both protocol versions work in parallel on the same Redis server. It is more sensible to enable RESP3 specifically where it provides a concrete benefit, for instance on connections intended to use client-side caching with tracking, while the rest of the application initially remains unchanged in RESP2 mode.
Before a broader rollout, it is worth running a trial against a staging environment under realistic load, paying specific attention to code that checks return types or processes raw protocol replies. Automated tests that verify typical command results such as HGETALL, ZSCORE, and SMEMBERS against expected data types reliably catch most practical pitfalls.
8. Backward compatibility: why RESP2 is not going away
Redis servers support RESP2 and RESP3 simultaneously and permanently; there is no announcement of RESP2 being deprecated anytime soon. This is a deliberate choice, since a vast ecosystem of existing applications, libraries, and tools is built on RESP2, and a forced switch would cause enormous compatibility problems. New features that technically depend on RESP3, such as the tracking protocol for client-side caching, therefore work exclusively over RESP3 connections, while the rest of Redis's functionality remains equally usable under both protocol versions.
In practice this means: RESP3 is not mandatory, it is an option to enable wherever it brings a concrete functional or structural benefit. Anyone who does not need any of the RESP3-exclusive features can stay on RESP2 permanently without any downside.
9. Debugging and diagnosis: identifying a connection's protocol version
When troubleshooting connection issues, it helps to know which protocol mode an existing connection is actually running in. The command CLIENT INFO returns, among other fields, the resp field, which shows the active protocol version for the calling connection, and CLIENT LIST provides the same information for all active connections on the server, which is useful for checking whether an expected RESP3 rollout has actually reached all relevant connections.
When unexpected application behavior appears after a partial RESP3 rollout, checking exactly this field is often a good first diagnostic step, since a forgotten HELLO 3 call in a particular connection pool configuration is a common but easily overlooked cause.
# Show the protocol version of the current connection
redis-cli -3 CLIENT INFO
# id=42 addr=... resp=3 ...
# List protocol versions of all active connections
redis-cli CLIENT LIST
| Aspect | RESP2 | RESP3 | Practical relevance |
|---|---|---|---|
| Map type | Encoded as a flat array | Explicit map with prefix % | HGETALL returns a genuine mapping |
| Set type | Encoded as an array | Explicit set with prefix ~ | Clearer semantics for unordered collections |
| Double type | Encoded as a bulk string | Genuine floating-point type with prefix , | ZSCORE returns a float directly instead of a string |
| Push messages | Not available | Dedicated type with prefix > | Prerequisite for tracking and PubSub separation |
| Activation | Default, no action needed | Explicit via HELLO 3 | Selectable per connection, no global switch required |
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
The RESP3 Protocol: The Essentials at a Glance
New data types
RESP3 introduces explicit maps, sets, doubles, booleans, big numbers, and an unambiguous null type instead of encoding everything as arrays or strings.
Push messages
The new push type allows server messages outside the normal request-response cycle and is a prerequisite for tracking-based client-side caching.
Activation
RESP3 is enabled per connection via HELLO 3, RESP2 remains the default and stays supported in parallel indefinitely.
Practical impact
Usually invisible with modern client libraries; the difference becomes noticeable in type checks and processing of raw protocol replies.