RESP
ActiveRESP (Redis Serialization Protocol) is the wire protocol used for communication between Redis clients and servers. RESP2 has been the standard since Redis 2.0. RESP3, designed by Salvatore Sanfilippo, was introduced as opt-in in Redis 6.0 and adds rich type semantics: maps, sets, doubles, booleans, nulls, verbatim strings, big numbers, and a push type for server-initiated out-of-band data. Clients activate RESP3 by sending the HELLO 3 command at connection startup.
In one line
RESP (Redis Serialization Protocol) is the text-based wire protocol for Redis client-server communication. RESP2 (Redis 2.0, 2010) encodes 5 types: simple string (+), error (-), integer (:), bulk string ($), array (*). RESP3 (Redis 6.0, 2020) is a superset adding 9 new types: null (_), double (,), boolean (#), blob error (!), verbatim string (=), big number ((), map (%), set (~), attribute (|), push (>). Clients upgrade via HELLO 3. RESP3 lets clients receive semantically typed replies (maps, sets) without knowing which command was called.
Quick Reference
| Field | Size | Description |
|---|---|---|
| RESP2 types | 5 types | + simple string, - error, : integer, $ bulk string, * array. All terminated by CRLF (\r\n). Bulk strings use length prefix: $11\r\nhello world\r\n. |
| RESP3 new types | 9 new types | _ null, , double, # boolean, ! blob error, = verbatim string, ( big number, % map, ~ set, | attribute, > push. All are superset additions – RESP2 types remain valid. |
| HELLO command | Protocol upgrade | HELLO 3 [AUTH username password] switches the connection to RESP3. Returns a map with server info (server, version, proto, id, mode, role, modules). HELLO 2 downgrades. If server returns -ERR unknown command, it only speaks RESP2. |
| Map type | % prefix | %<count>\r\n followed by count×2 elements (key-value pairs). %2\r\n+first\r\n:1\r\n+second\r\n:2\r\n represents {first:1, second:2}. HGETALL now returns a map instead of a flat array. |
| Set type | ~ prefix | ~<count>\r\n followed by count elements. ~3\r\n+a\r\n+b\r\n+c\r\n represents {a, b, c}. SMEMBERS now returns a set instead of an array. |
| Push type | > prefix | Out-of-band server push, format like array but > prefix. First element is the push type string (pubsub, monitor). Client handles push without affecting command reply ordering. Enables pub/sub on shared connections. |
| Null type | _ alone | _\r\n replaces RESP2's dual null representations ($-1 null bulk and *-1 null array). One null type for all null values. |
| Inline commands | Space-separated | Simple commands can be sent inline without RESP framing: PING\r\n or SET key value\r\n. Only for human/debugging use. Not for client libraries. |
| Pipelining | Multiple commands | Client sends N commands without waiting for replies. Server processes and replies in order. Reduces round trips. RESP2 and RESP3 both support pipelining. Not the same as multiplexing – replies are ordered. |
Key Characteristics
Type-aware replies
RESP3's core value: HGETALL returns a % map, SMEMBERS returns a ~ set, ZADD scores return , doubles. Client libraries can return native dict/set/float without needing to know which command was called.
Push on shared connections
RESP3's > push type allows pub/sub messages and keyspace notifications to arrive on any connection without switching modes. RESP2 required a dedicated pub/sub connection; RESP3 allows subscribing and issuing commands on the same connection.
Backward compatible
RESP3 is a superset of RESP2. Existing RESP2 clients work unchanged against RESP3-capable servers. Only clients that send HELLO 3 receive new type semantics. Servers respond to non-HELLO clients with RESP2 encoding.
CRLF requirement
All RESP lines are terminated by \r\n (CRLF), not just \n. Sending LF-only terminators produces parse errors. This applies to both RESP2 and RESP3.
Message Format
# Client sends HELLO 3 to upgrade connection
C: HELLO 3
S: %7
# map reply with 7 fields
+server
+redis
+version
+7.2.0
+proto
:3
+id
:42
+mode
+standalone
+role
+master
+modules
*0
# RESP2: SET key value (array of bulk strings)
*3
$3
SET
$3
foo
$3
bar
# S: +OK
# RESP3: HGETALL returns a map instead of flat array
*2
$7
HGETALL
$6
myhash
# S (RESP2): *4
+f1
+v1
+f2
+v2
(flat array)
# S (RESP3): %2
+f1
+v1
+f2
+v2
(map – client knows it's a dict)# RESP3 type prefix reference:
# + simple string +OK
# - simple error -ERR wrong type
# : integer :42
# $ bulk string $5
hello
# * array *2
:1
:2
# _ null _
# , double ,3.14159
or ,inf
# # boolean #t
or #f
# ! blob error !21
SYNTAX invalid
# = verbatim string =15
txt:Some string
# ( big number (3492890328409238509324850943
# % map %2
+key1
:1
+key2
:2
# ~ set ~3
+a
+b
+c
# | attribute |1
+key-popularity
%2
...
# > push >4
+pubsub
+message
+chan
+payload
# SMEMBERS in RESP2 vs RESP3:
# RESP2: *3
$5
apple
$6
banana
$6
cherry
(array)
# RESP3: ~3
$5
apple
$6
banana
$6
cherry
(set)
# Client can return Python set() or Ruby Set without checking command name