diff --git a/content/develop/reference/protocol-spec.md b/content/develop/reference/protocol-spec.md
index c36009d20f..93ec6a490f 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 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:
+
+ $?\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: