The RESP3 Protocol: What Actually Changes Compared to RESP2
AI generated
SET
TTL
Redis · RESP3 · Protocol
The RESP3 Protocol
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.

11 min read RESP3 · RESP2 HELLO · Push Messages

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.

11. FAQ: The RESP3 Protocol: The Essentials at a Glance

1What is the fundamental difference between RESP2 and RESP3?
RESP2 encodes all more complex structures as flat arrays or strings, while RESP3 introduces explicit types for maps, sets, doubles, booleans, and push messages that more precisely capture what a command returns.
2How does a client enable RESP3?
Via the HELLO 3 command right after connecting, where HELLO can additionally handle authentication and database selection in a single round trip.
3Does the entire application need to switch to RESP3 at once?
No, the protocol switch applies per connection, so different connections within the same application can use different protocol versions.
4Which new feature strictly requires RESP3?
Client-side caching with the tracking protocol needs RESP3's push messages, since RESP2 has no mechanism for server messages outside the normal request-response cycle.
5Will RESP2 be deprecated in the future?
No, there is no announcement to deprecate RESP2. Both protocol versions are supported permanently in parallel to avoid endangering the vast existing ecosystem.
6How does ZSCORE's reply differ between RESP2 and RESP3?
Under RESP2, ZSCORE returns a bulk string that must be parsed as a number, while under RESP3 it returns a genuine double value that the client library passes through directly as a float.
7Do all Redis client libraries support RESP3 equally well?
No, mature, actively maintained libraries usually offer explicit RESP3 support, while older or less maintained libraries may return protocol errors or silently ignore the new types.
8How do you check which protocol mode an existing connection is running in?
With CLIENT INFO or CLIENT LIST, which show the active protocol version for the respective connection in the resp field.
9Which code locations are most likely affected by a RESP3 switch?
Code that explicitly checks return types, for instance with is_string() or is_array(), as well as code that processes raw protocol replies for debugging or logging.
10Should RESP3 be enabled across the entire application immediately?
Not necessarily. A gradual rollout where it brings a concrete benefit, combined with targeted tests against typical command results before a broader switch, is generally more sensible.