From a736f4a06a201050e5fb3c8279c4097115c23bf5 Mon Sep 17 00:00:00 2001 From: Andy Stark Date: Wed, 26 Aug 2026 13:47:18 +0100 Subject: [PATCH 1/2] DOC-7003 document RESP3 streamed types in the protocol spec MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds the two streamed encodings from the RESP3 specification as sections on the protocol spec page, plus a short pointer explaining why the RESP data type table doesn't list them. These sections exist to be linked to. lua-api.md carries 18 anchored links into the upstream RESP3.md on master; 7 of its 11 distinct anchors are dead, and two of those name streamed types our own page had no equivalent for — the only trace was one clause in the RESP versions paragraph. The other dead anchors retarget cleanly onto existing sections. These two had nowhere to go, which is why they land first in the stack. The tempting move was to add rows to the RESP data type table, and it would have been wrong twice over. That table is introduced as the types Redis supports, and the RESP versions paragraph records that Redis 6.0's RESP3 support excluded streaming strings and aggregates. A row would assert support we have no source for and quietly soften a documented limitation. The sections sit outside the table instead, framed as alternative encodings of existing types, with support stated only in sourced terms. The headings were chosen to slugify to the same anchors the upstream spec uses, so a corrected link reads identically whether it points here or at the spec. That makes the aggregated/aggregate spelling load-bearing — the shorter spelling is exactly what was dead upstream. Anchors were verified against the built HTML, with a check that the misspelled variant is absent, so the fix is real at the target end rather than a slug prediction. Learned: our protocol page documents what Redis emits, not everything RESP3 defines, so a spec feature Redis omits belongs beside the type table and never in it. Constraint: the heading must slugify to streamed-aggregated-data-types; the shorter aggregate spelling is the upstream anchor that was already dead. Rejected: adding streamed types to the RESP data type table | asserts support we have no source for and softens the Redis 6.0 exclusion the page already documents Directive: don't delete these as undocumented-feature cruft — lua-api.md links into them, and Redis not emitting them is the point they carry. Gaps: whether Redis 7 or 8 emits streamed types is unverified; only the Redis 6 position is sourced, from the page itself and the spec. Recheck: if Redis ever implements streamed types, revisit both support sentences and the RESP versions paragraph Ticket: DOC-7003 Co-Authored-By: Claude Opus 5 (1M context) --- content/develop/reference/protocol-spec.md | 60 ++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/content/develop/reference/protocol-spec.md b/content/develop/reference/protocol-spec.md index c36009d20f..cf7004b4ac 100644 --- a/content/develop/reference/protocol-spec.md +++ b/content/develop/reference/protocol-spec.md @@ -139,6 +139,9 @@ The following table summarizes the RESP data types that Redis supports: | [Sets](#sets) | RESP3 | Aggregate | `~` | | [Pushes](#pushes) | RESP3 | Aggregate | `>` | +RESP3 also defines two _streamed_ encodings for payloads whose length isn't known when the transfer begins: [streamed strings](#streamed-strings) and [streamed aggregated data types](#streamed-aggregated-data-types). +These are alternative encodings of the types in the table rather than types of their own, so the table doesn't list them. + ### Simple strings @@ -623,6 +626,63 @@ It also means that pushed data may appear before or after a command's reply, as Clients should react to pushes by invoking a callback that implements their handling of the pushed data. +### Streamed strings +A streamed string is a [bulk string](#bulk-strings) whose total length isn't known when the transfer begins. +Instead of a prefixed length, the sender transfers the payload as a series of chunks. + +A streamed string's RESP encoding is as follows: + + $?\r\n;\r\n\r\n...;0\r\n + +* A dollar sign (`$`) as the first byte, followed by a question mark (`?`) in place of the length. +* The CRLF terminator. +* One or more chunks. Each chunk is a semicolon (`;`), the chunk's length in bytes as an unsigned, base-10 value, the CRLF terminator, the chunk's data, and a final CRLF. +* A zero-length chunk (`;0\r\n`) to mark the end of the string. + +Example: + + $?\r\n + ;5\r\n + Hello\r\n + ;6\r\n + world\r\n + ;0\r\n + +(The raw RESP encoding is split into multiple lines for readability). + +The chunks concatenate to the string's value, so the example encodes `Hello world`. + +Redis doesn't emit streamed strings, because its RESP3 support excludes streamed types (see [RESP versions](#resp-versions)). +The [RESP3 specification](https://github.com/redis/redis-specifications/blob/1252427cdbc497f66a7f8550c6b5f2f35367dc92/protocol/RESP3.md#streamed-strings) permits modules to use the encoding, so a client that implements RESP3 in full should be able to parse it. + +### Streamed aggregated data types +[Arrays](#arrays), [sets](#sets), and [maps](#maps) can also be streamed when the number of elements isn't known when the transfer begins. +A streamed aggregate replaces its number of elements with a question mark (`?`) and marks its end with a dedicated terminator. + +A streamed aggregate's RESP encoding is as follows: + + ?\r\n....\r\n + +* The aggregate's usual first byte: an asterisk (`*`) for an array, a tilde (`~`) for a set, or a percent sign (`%`) for a map. +* A question mark (`?`) in place of the number of elements. +* The CRLF terminator. +* An additional RESP type for every element of the aggregate. +* A period (`.`) followed by the CRLF terminator to mark the end of the aggregate. + +Example: + + *?\r\n + :1\r\n + :2\r\n + :3\r\n + .\r\n + +(The raw RESP encoding is split into multiple lines for readability). + +A streamed map's elements are field-value pairs, as in a regular [map](#maps), so a streamed map must contain an even number of elements. + +As with [streamed strings](#streamed-strings), Redis doesn't emit streamed aggregates. + ## Client handshake New RESP connections should begin the session by calling the [`HELLO`]({{< relref "/commands/hello" >}}) command. This practice accomplishes two things: From 7138f54cfbc680e134e2a1e3d5068d71f95efde1 Mon Sep 17 00:00:00 2001 From: andy-stark-redis <164213578+andy-stark-redis@users.noreply.github.com> Date: Wed, 26 Aug 2026 14:46:21 +0100 Subject: [PATCH 2/2] Update content/develop/reference/protocol-spec.md Co-authored-by: David Dougherty --- content/develop/reference/protocol-spec.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/develop/reference/protocol-spec.md b/content/develop/reference/protocol-spec.md index cf7004b4ac..93ec6a490f 100644 --- a/content/develop/reference/protocol-spec.md +++ b/content/develop/reference/protocol-spec.md @@ -636,7 +636,7 @@ A streamed string's RESP encoding is as follows: * A dollar sign (`$`) as the first byte, followed by a question mark (`?`) in place of the length. * The CRLF terminator. -* One or more chunks. Each chunk is a semicolon (`;`), the chunk's length in bytes as an unsigned, base-10 value, the CRLF terminator, the chunk's data, and a final CRLF. +* One or more chunks. Each chunk starts with a semicolon (`;`), followed by the chunk's length in bytes as an unsigned, base-10 value, the CRLF terminator, the chunk's data, and a final CRLF. * A zero-length chunk (`;0\r\n`) to mark the end of the string. Example: