Yuvraj Singh Chauhan
Back to blog

Demystifying RESP: The Engine Behind Redis Communication

June 13, 20264 min read
SWE: Database Internals

When you type a command like SET key value into your Redis CLI, how exactly does the server understand it? It relies on a specific wire protocol known as the Redis Serialization Protocol, or RESP.

While Redis is famous for its in-memory speed, its choice of communication protocol is equally crucial to its performance. RESP is designed over TCP to be a request-response protocol that perfectly balances three competing needs: it is simple to implement, incredibly fast to parse, and human-readable.

For a student diving into database internals, understanding RESP offers a masterclass in how to format data for low-latency network transmission.

The Core Pattern of RESP

Every piece of data sent over RESP follows a strict, predictable pattern that makes parsing effortless. The protocol relies on three fundamental rules:

  1. The Prefix Byte: The very first byte of any RESP payload identifies the data type that follows.
  2. The Data: The actual content being transmitted.
  3. The Terminator: Every part of the protocol is separated and terminated by a Carriage Return and Line Feed sequence, represented as CRLF (\r\n).

Understanding the Data Types

RESP categorizes data into simple types (scalars) and aggregate types (collections). Here is how the most common types are encoded under the hood:

1. Simple Strings (+) Used for short, simple responses like "OK" or "PONG". They are encoded with a plus sign, followed by the string, and ended with CRLF.

  • Encoding: +PONG\r\n
  • Why use it? It carries incredibly low memory overhead. However, simple strings are not "binary safe"—they cannot contain a \r or \n character within the string itself, as the parser would prematurely stop reading.

2. Simple Errors (-) Errors are formatted identically to simple strings but start with a minus sign. This tells the client library to treat the response as an exception rather than standard data.

  • Encoding: -ERR unknown command\r\n

3. Integers (:) Used to represent 64-bit signed integers. They start with a colon.

  • Encoding: :1000\r\n

4. Bulk Strings ($) - The Binary-Safe Solution If simple strings aren't binary safe, how does Redis store complex data like serialized objects, documents, or even images? It uses Bulk Strings, which start with a dollar sign. To prevent the parser from getting confused by random \r\n bytes inside the data, Bulk Strings use a prefixed length. You tell the server exactly how many bytes the string is before sending the string itself.

  • Encoding: $4\r\npong\r\n (Here, 4 indicates the string is exactly 4 bytes long).
  • Null Values: In RESP2, a lack of data (null) is cleverly represented as a bulk string with a negative length: $-1\r\n.

5. Arrays (*) Arrays are how clients actually send commands to the Redis server. An array starts with an asterisk, followed by the number of elements it contains, and then the elements themselves (which can be of mixed data types).

  • Encoding: If you want to send the command GET cat, the client sends an array of two bulk strings: *2\r\n$3\r\nGET\r\n$3\r\ncat\r\n.

The Intuition: Why is RESP so Fast?

You might wonder why Redis created a custom protocol instead of just using JSON. The answer lies in CPU efficiency and network I/O optimization.

  • Zero-Scanning Parsing: Parsing JSON is CPU-intensive. A JSON parser must read the payload byte-by-byte, constantly searching for unescaped quotation marks or brackets to figure out where a string ends. RESP entirely bypasses this.
  • The Power of Prefixed Lengths: Because aggregate types like Bulk Strings and Arrays declare their size upfront (e.g., $5\r\n), the parser doesn't need to inspect the payload at all.
  • Predictable Memory Allocation: When the underlying C code sees a bulk string length of 5, it instantly makes a single blocking network read for exactly 5 bytes and allocates a buffer of exactly that size. It knows exactly when the data ends, making parsing comparable in speed to complex binary protocols, while remaining text-based and easy to debug.

The Evolution: RESP3

While RESP2 handled Redis's core needs perfectly, Redis 6 introduced RESP3. RESP3 is largely a superset of RESP2 designed to make life easier for client library developers. While RESP2 forced complex data structures to be returned as flat arrays, RESP3 introduced dedicated semantic types.

New prefix bytes in RESP3 include Maps (%), Sets (~), Doubles (,), true Nulls (_), and Booleans (#). This allows client libraries to instantly convert Redis responses into native programming language dictionaries, hash sets, and boolean types without needing to infer the structure from a flat array.

By combining the readability of text formats with the memory-allocation efficiency of binary protocols, RESP acts as the unseen engine ensuring Redis never wastes a CPU cycle when talking to your application.