Logo
Redis Protocol (RESP): How Redis Understands Your Commands
Overview

Redis Protocol (RESP): How Redis Understands Your Commands

December 30, 2025
9 min read

How Does Redis Understand Your Commands?

When you fire a command like:

SET username alice

Redis doesn’t magically understand English. Your client needs to translate it into a format Redis can parse. This is where RESP comes in.

RESP stands for REdis Serialization Protocol. It’s the language that clients and servers speak to understand each other.

Without a standardized protocol, every Redis client (Node.js, Python, Go, etc.) would need its own custom way to communicate. Chaos.

Instead, Redis defined RESP, and every client follows it. Simple. Elegant.


Part 1: What Is RESP?

The Basic Idea

When you send a command to Redis, it needs to be serialized (converted into a specific format). RESP is that format.

Example:

You want to execute:

SET key value

Your client serializes it as:

*3\r\n
$3\r\n
SET\r\n
$3\r\n
key\r\n
$5\r\n
value\r\n

Let’s break this down:

  • *3 = “This is an array with 3 elements”
  • $3 = “Next element is a bulk string with 3 bytes”
  • SET = The actual command
  • $3 = “Next element is 3 bytes”
  • key = The actual key
  • $5 = “Next element is 5 bytes”
  • value = The actual value
  • \r\n = Line terminator (CRLF) after every line

Redis reads this, understands it’s a 3-element array, parses each bulk string, and executes the command.

Why RESP?

Protocol Requirements:

  1. Must be unambiguous (no guessing)
  2. Must be fast to parse
  3. Should handle binary data
  4. Should be reasonably human-readable

RESP nails all of these. It’s the opposite of overly complex formats. It’s simple, fast, and efficient.


Part 2: RESP Data Types

RESP supports several data types. Each one starts with a special character that tells Redis what to expect.

1. Simple Strings

Format: +<string>\r\n

Starts with: + (plus sign)

Example:

+OK\r\n

Redis sends this when a command succeeds. OK means the operation was successful.

Another example:

+PONG\r\n

When you send PING, Redis responds with +PONG\r\n.

Overhead: A simple string response requires n + 3 bytes (string length + 1 for + + 2 for \r\n).

When to use: Quick confirmations, status messages. Minimal overhead.

Note

Important: Simple strings can’t contain \r\n because that’s the terminator. If you need to send arbitrary text with line breaks, use bulk strings instead.

2. Integers

Format: :<integer>\r\n

Starts with: : (colon)

Example:

:1729\r\n

When you execute INCR counter, Redis increments the counter and responds with the new value as an integer.

Real example:

ZADD leaderboard 100 alice
// Redis responds: :1\r\n (meaning 1 element was added)
GET counter
// Redis responds: :5\r\n (the counter value is 5)

When to use: Counts, scores, ranks, any numeric response.

3. Bulk Strings

Format: $<length>\r\n<data>\r\n

Starts with: $ (dollar sign)

Example:

$4\r\nPONG\r\n

Breaking it down:

  • $4 = “The following data is 4 bytes”
  • PONG = The actual data
  • \r\n = Terminator

Another example:

$11\r\nHello World\r\n

Why Bulk Strings When Simple Strings Exist?

  1. Binary safety: Bulk strings can contain ANY byte, including \r\n. Perfect for storing images, binary data, or text with special characters.
  2. Known length: The $4 tells the parser exactly how many bytes to read. No ambiguity.
  3. Flexibility: Simple strings fail when data contains the terminator. Bulk strings don’t.

Example of Why Binary Safety Matters:

// If you tried to send this as a simple string:
+ This is a\r\ntricky string\r\n
// The parser would think it's done after the first \r\n
// It would read "This is a" and stop
// But as a bulk string:
$18\r\nThis is a\r\ntricky string\r\n
// The parser knows to read exactly 18 bytes, even if they contain \r\n

Special Bulk Strings

Empty string:

$0\r\n\r\n

“Zero bytes of data, followed by terminator.”

Null string (absence of data):

$-1\r\n

The length -1 is a special sentinel value meaning “no data exists.” Used when a key doesn’t exist, for example.

GET nonexistent_key
// Redis responds: $-1\r\n (key not found)

When to use: Storing text, binary data, images, or any response from Redis that isn’t a simple status message.

4. Arrays

Format: *<count>\r\n<elements>\r\n

Starts with: * (asterisk)

Example:

*3\r\n
$3\r\nSET\r\n
$3\r\nkey\r\n
$5\r\nvalue\r\n

This is an array with 3 elements:

  1. “SET”
  2. “key”
  3. “value”

Real Redis Response Example:

When you execute MGET key1 key2 key3, Redis returns an array of values:

*3\r\n
$5\r\nvalue1\r\n
$5\r\nvalue2\r\n
$5\r\nvalue3\r\n

This means: “Array with 3 elements: ‘value1’, ‘value2’, ‘value3’.”

Empty Array

*0\r\n

“An array with zero elements.” Rare in practice.

Null Array

*-1\r\n

“No array exists.” Similar to null string, but for arrays.

Nested Arrays

Arrays can contain other arrays (or any RESP type):

*2\r\n
*2\r\n
$3\r\nfoo\r\n
$3\r\nbar\r\n
*2\r\n
$4\r\nhello\r\n
$5\r\nworld\r\n

This is:

[
["foo", "bar"],
["hello", "world"]
]

When to use: Returning multiple values, bulk operations, results from scanning, etc.

Note

Parser Trick: Because arrays have a prefix length (*3 means 3 elements), the parser knows exactly how many elements to expect. It doesn’t have to guess when the array ends. This makes parsing fast and unambiguous.

5. Errors

Format: -<error message>\r\n

Starts with: - (hyphen)

Example:

-ERR unknown command 'SET'\r\n

or

-WRONGTYPE Operation against a key holding the wrong kind of value\r\n

When Redis encounters an error, it responds with a message prefixed by -. The client detects the - and knows it’s an error.

When to use: When something goes wrong—syntax error, wrong key type, permission denied, etc.


Part 3: RESP in Action

Example 1: Setting a Key-Value Pair

You execute:

SET username alice

Client serializes (RESP):

*3\r\n
$3\r\n
SET\r\n
$8\r\n
username\r\n
$5\r\n
alice\r\n

Redis parses:

  • *3 → Expecting 3 elements
  • $3\r\nSET\r\n → First element: bulk string “SET”
  • $8\r\nusername\r\n → Second element: bulk string “username”
  • $5\r\nalice\r\n → Third element: bulk string “alice”

Redis executes: Stores username = alice in memory

Redis responds:

+OK\r\n

Example 2: Getting a Non-Existent Key

You execute:

GET nonexistent

Client serializes:

*2\r\n
$3\r\n
GET\r\n
$11\r\n
nonexistent\r\n

Redis responds (key not found):

$-1\r\n

The -1 tells the client: “This key doesn’t exist.”

Example 3: Getting Multiple Keys

You execute:

MGET key1 key2 key3

Client serializes:

*4\r\n
$4\r\n
MGET\r\n
$4\r\n
key1\r\n
$4\r\n
key2\r\n
$4\r\n
key3\r\n

Redis responds (assuming key1=“value1”, key2=“value2”, key3 doesn’t exist):

*3\r\n
$6\r\n
value1\r\n
$6\r\n
value2\r\n
$-1\r\n

An array with 3 elements: “value1”, “value2”, and null (key3 doesn’t exist).


Part 4: Why RESP Is Brilliant

1. Human-Readable

*3\r\n
$3\r\nSET\r\n
$3\r\nkey\r\n
$5\r\nvalue\r\n

If you print this to the console, you can understand it. Compare this to binary protocols where you see hex dumps. RESP is debuggable.

2. Simple to Parse

Each line starts with a type indicator (+, :, $, *, -). The parser doesn’t need complex logic. Read the first character, figure out what type it is, parse accordingly.

No complex state machines. No ambiguity.

3. Performant

  • Prefix length: You know upfront how many bytes to read ($4 = read 4 bytes). No scanning for the end.
  • Linear parsing: Read line by line, process, move on. No backtracking.
  • Minimal overhead: A simple string response is just +PONG\r\n (7 bytes). Compare to JSON:
{"status": "success"} // 22 bytes

RESP wins for small responses.

4. Binary Safe

Bulk strings can contain any byte sequence, including \r\n. This is critical for storing images, PDFs, serialized objects, etc.


Part 5: RESP Version 2 vs RESP3

Redis introduced RESP3 in version 6.0 to support additional data types (sets, maps, etc. as distinct types, not just arrays).

However, RESP2 is still widely used and understood. For this discussion, we focused on RESP2.

Key difference:

  • RESP2: Simpler, older, still predominant
  • RESP3: Supports more native data types, better for clients

Part 6: How This Matters in Practice

When You Use a Redis Client Library

You never manually construct RESP messages. Your client library does it for you.

Node.js example:

const redis = require('redis');
const client = redis.createClient();
client.set('username', 'alice', (err, reply) => {
// Under the hood, the client serialized to RESP,
// sent it to Redis, received the response,
// and deserialized it back to JavaScript
});

The library abstracts away RESP. But knowing it exists helps you understand:

  1. Why certain data types exist – RESP supports strings, integers, arrays, and errors, so Redis clients mirror these
  2. Why binary safety matters – Bulk strings enable it
  3. Why responses are fast – RESP is minimal overhead

When Debugging

If you’re using redis-cli or debugging a network issue, you might see RESP directly:

Terminal window
$ nc localhost 6379
*3\r\n
$3\r\n
SET\r\n
$3\r\n
key\r\n
$5\r\n
value\r\n
+OK\r\n

Understanding RESP helps you read these raw messages.


Part 7: Comparing RESP to Other Protocols

RESP vs JSON

JSON:

{
"command": "SET",
"key": "username",
"value": "alice"
}

Problems:

  • Larger (more bytes)
  • Requires parsing (quote detection, escape handling)
  • Not binary-safe (need Base64 encoding for binary data)
  • Overhead for nested structures

RESP:

*3\r\n
$3\r\nSET\r\n
$8\r\nusername\r\n
$5\r\nalice\r\n

Advantages:

  • Compact
  • Fast to parse (no complex logic)
  • Binary-safe
  • Minimal overhead

For a high-performance protocol like Redis, RESP is superior.

RESP vs gRPC

gRPC uses Protocol Buffers (binary, typed, more complex).

RESP is simpler, text-based, and more human-debuggable.

The trade-off: gRPC is better for large-scale distributed systems; RESP is better for simplicity and speed in a single service.


Part 8: Summary: The RESP Protocol

TypeStartFormatExample
Simple String++OK\r\nConfirmations, simple responses
Error--ERR message\r\nError messages
Integer::42\r\nCounts, scores, numeric responses
Bulk String$$3\r\nSET\r\nText, binary data, large strings
Array**2\r\n$3\r\nkey\r\n$5\r\nvalue\r\nMultiple values, complex responses

Key Principles:

  • Every RESP message is unambiguous
  • Prefix length enables fast, non-blocking parsing
  • Binary safe (bulk strings)
  • Human-readable
  • Minimal overhead

Conclusion

RESP is the foundation of Redis communication. It’s not something you usually think about when using Redis—your client library handles it automatically.

But understanding RESP:

  1. Demystifies how clients and servers talk
  2. Helps debug network issues
  3. Explains why certain design choices exist in Redis
  4. Improves your mental model of how Redis works

Further Reading