# RESP3

> Switch a connection to RESP3 with HELLO 3, and see how replies change: maps, sets, doubles, nulls, verbatim strings and push messages.

URL: https://docs.hotkv.com/develop/resp3/


HotKV speaks both versions of the Redis serialization protocol. Every
connection starts in RESP2, the protocol every Redis client understands.
RESP3 adds reply types that say what the data is (a map, a set, a
floating-point number, a null) so that client libraries can turn replies
into native types without knowing each command's reply shape, and it adds
push messages for out-of-band data such as Pub/Sub messages.

All official HotKV SDKs (Python, Node.js, Go, Java) ask for RESP3 when they
connect and fall back to RESP2 automatically. You only need this page if you
write a client, read raw replies, or want to understand why a reply looks
different in `redis-cli -3`.

## Switching protocols with HELLO

[HELLO](https://docs.hotkv.com/commands/hello/index.md) `[protover [AUTH username password] [SETNAME clientname]]`
switches the connection's protocol and replies with information about the
server. `protover` is `2` or `3`; any other value replies
`NOPROTO unsupported protocol version`. Without arguments, `HELLO` replies
without changing the protocol.

```
127.0.0.1:6379> HELLO 3
1# "server" => "hotkv"
2# "version" => "8.4.0"
3# "proto" => (integer) 3
4# "id" => (integer) 7
5# "mode" => "standalone"
6# "role" => "master"
7# "modules" => (empty array)
```

| Field | Value |
| --- | --- |
| `server` | Always `hotkv` |
| `version` | The Redis version HotKV is compatible with, `8.4.0`. Client libraries use it to decide which commands they can send. [INFO](https://docs.hotkv.com/commands/info/index.md) `server` shows HotKV's own version. |
| `proto` | The protocol now in use |
| `id` | The connection's client id, as in [CLIENT ID](https://docs.hotkv.com/commands/client-id/index.md) |
| `mode` | `standalone` or `cluster` |
| `role` | `master` or `replica` |
| `modules` | Always empty: HotKV does not load modules |

`AUTH` authenticates in the same step, which is how a client connects to a
server that requires a password without a separate [AUTH](https://docs.hotkv.com/commands/auth/index.md)
command. On such a server, `HELLO` without `AUTH` from a connection that has
not authenticated replies `NOAUTH`. `SETNAME` sets the connection name, as
[CLIENT SETNAME](https://docs.hotkv.com/commands/client-setname/index.md) does.

`HELLO 2` switches back to RESP2. [RESET](https://docs.hotkv.com/commands/reset/index.md) also returns the
connection to RESP2, along with the rest of its initial state.

## How replies change

The data is the same in both protocols; only the encoding changes.

| Reply | RESP2 | RESP3 |
| --- | --- | --- |
| Missing value (`GET` of a missing key, `BLPOP` timeout, ...) | Nil bulk string or nil array | Null (`_`) |
| Field-value pairs (`HGETALL`, `CONFIG GET`, ...) | Flat array: field, value, field, value | Map (`%`) |
| Unordered members (`SMEMBERS`, ...) | Array | Set (`~`) |
| Scores and coordinates (`ZSCORE`, ...) | Bulk string such as `"1.5"` | Double (`,`) |
| Yes/no answers of Bloom filter commands | Integer `1` or `0` | Boolean (`#t` / `#f`) |
| Human-readable reports (`INFO`, ...) | Bulk string | Verbatim string (`=`) with format `txt` |
| Pub/Sub messages | Array | Push (`>`) |

```
127.0.0.1:6379> HSET user:42 name "Ada" lang "en"
(integer) 2
127.0.0.1:6379> HGETALL user:42
1) "name"
2) "Ada"
3) "lang"
4) "en"
127.0.0.1:6379> HELLO 3
...
127.0.0.1:6379> HGETALL user:42
1# "name" => "Ada"
2# "lang" => "en"
127.0.0.1:6379> ZADD board 1.5 ada
(integer) 1
127.0.0.1:6379> ZSCORE board ada
(double) 1.5
127.0.0.1:6379> GET missing
(nil)
```

Integers, simple strings, bulk strings, errors and plain arrays look the same
in both protocols.

## Commands whose replies change

**Maps.** [HGETALL](https://docs.hotkv.com/commands/hgetall/index.md), [CONFIG GET](https://docs.hotkv.com/commands/config-get/index.md),
[HELLO](https://docs.hotkv.com/commands/hello/index.md), [XREAD](https://docs.hotkv.com/commands/xread/index.md) and
[XREADGROUP](https://docs.hotkv.com/commands/xreadgroup/index.md) (a map from stream name to entries),
[XINFO STREAM](https://docs.hotkv.com/commands/xinfo-stream/index.md), [LCS](https://docs.hotkv.com/commands/lcs/index.md) with `IDX`,
[MEMORY STATS](https://docs.hotkv.com/commands/memory-stats/index.md),
[LATENCY HISTOGRAM](https://docs.hotkv.com/commands/latency-histogram/index.md),
[ACL GETUSER](https://docs.hotkv.com/commands/acl-getuser/index.md), [FUNCTION LIST](https://docs.hotkv.com/commands/function-list/index.md)
and [FUNCTION STATS](https://docs.hotkv.com/commands/function-stats/index.md),
[CLIENT TRACKINGINFO](https://docs.hotkv.com/commands/client-trackinginfo/index.md),
[CLUSTER LINKS](https://docs.hotkv.com/commands/cluster-links/index.md),
[CLUSTER SLOT-STATS](https://docs.hotkv.com/commands/cluster-slot-stats/index.md),
[BF.INFO](https://docs.hotkv.com/commands/bf-info/index.md), [CMS.INFO](https://docs.hotkv.com/commands/cms-info/index.md) and
[TOPK.INFO](https://docs.hotkv.com/commands/topk-info/index.md).

**Sets.** [SMEMBERS](https://docs.hotkv.com/commands/smembers/index.md), [SINTER](https://docs.hotkv.com/commands/sinter/index.md),
[SUNION](https://docs.hotkv.com/commands/sunion/index.md), [SDIFF](https://docs.hotkv.com/commands/sdiff/index.md),
[SPOP](https://docs.hotkv.com/commands/spop/index.md) with a count, and the flag lists in
[COMMAND INFO](https://docs.hotkv.com/commands/command-info/index.md) and `FUNCTION LIST`.

**Doubles.** [ZSCORE](https://docs.hotkv.com/commands/zscore/index.md), [ZMSCORE](https://docs.hotkv.com/commands/zmscore/index.md),
[ZINCRBY](https://docs.hotkv.com/commands/zincrby/index.md), [ZADD](https://docs.hotkv.com/commands/zadd/index.md) with `INCR`,
[ZRANK](https://docs.hotkv.com/commands/zrank/index.md) and [ZREVRANK](https://docs.hotkv.com/commands/zrevrank/index.md) with
`WITHSCORE`, the pop commands ([ZPOPMIN](https://docs.hotkv.com/commands/zpopmin/index.md),
[ZPOPMAX](https://docs.hotkv.com/commands/zpopmax/index.md), [BZPOPMIN](https://docs.hotkv.com/commands/bzpopmin/index.md),
[BZPOPMAX](https://docs.hotkv.com/commands/bzpopmax/index.md), [ZMPOP](https://docs.hotkv.com/commands/zmpop/index.md),
[BZMPOP](https://docs.hotkv.com/commands/bzmpop/index.md)), and coordinates from
[GEOPOS](https://docs.hotkv.com/commands/geopos/index.md) and `WITHCOORD`.

**Scores with members.** Commands with `WITHSCORES`, such as
[ZRANGE](https://docs.hotkv.com/commands/zrange/index.md) and [ZRANDMEMBER](https://docs.hotkv.com/commands/zrandmember/index.md), reply
with a flat array (member, score, member, score) in RESP2 and with an array
of `[member, score]` pairs, each score a double, in RESP3:

```
127.0.0.1:6379> ZRANGE board 0 -1 WITHSCORES
1) 1) "ada"
   2) (double) 1.5
```

**Booleans.** [BF.ADD](https://docs.hotkv.com/commands/bf-add/index.md), [BF.MADD](https://docs.hotkv.com/commands/bf-madd/index.md),
[BF.INSERT](https://docs.hotkv.com/commands/bf-insert/index.md), [BF.EXISTS](https://docs.hotkv.com/commands/bf-exists/index.md) and
[BF.MEXISTS](https://docs.hotkv.com/commands/bf-mexists/index.md).

**Verbatim strings.** [INFO](https://docs.hotkv.com/commands/info/index.md),
[CLIENT LIST](https://docs.hotkv.com/commands/client-list/index.md), [CLIENT INFO](https://docs.hotkv.com/commands/client-info/index.md),
and the `DOCTOR` reports of [MEMORY](https://docs.hotkv.com/commands/memory/index.md) and
[LATENCY](https://docs.hotkv.com/commands/latency/index.md).

## Push messages

In RESP3, data the client did not ask for in a reply arrives as a push frame,
so a client can tell it apart from command replies on the same connection.
HotKV sends push frames for:

- Pub/Sub messages (`message`, `pmessage`, `smessage`) and subscription
  confirmations (`subscribe`, `unsubscribe`, and their pattern and shard
  versions). See [Pub/Sub](https://docs.hotkv.com/develop/pubsub/index.md).
- `sunsubscribe` notices when a cluster slot moves away and its shard
  channel subscriptions end.
- Client-side caching invalidations (`invalidate`, with the keys or a null)
  and `tracking-redir-broken`, for a connection that turned on
  [`CLIENT TRACKING`](https://docs.hotkv.com/commands/client-tracking/index.md). See
  [Client-side caching](https://docs.hotkv.com/develop/client-side-caching/index.md).

> **Note**
> A RESP3 connection that is subscribed to channels can run any command, because
> its messages arrive as pushes that are told apart from replies. A RESP2
> connection with subscriptions is limited to subscription commands, `PING`,
> `QUIT` and `RESET`.

## Scripts and RESP3

Inside a [Lua script](https://docs.hotkv.com/develop/lua-scripting/index.md), `redis.call()` returns
replies converted from RESP2 unless the script calls `redis.setresp(3)`.
After `redis.setresp(3)`, maps, sets, doubles, booleans and big numbers come
into the script as tables such as `{map = {...}}`, `{double = 1.5}` or
`{big_number = "..."}`, and a script can return those tables to send the
matching RESP3 type to a RESP3 client. A RESP2 client gets the RESP2 form of
the same data.

## Compatibility

`HELLO`, the RESP3 reply types and push messages follow Redis 7, and the
invalidation pushes of client-side caching follow Redis 8 and Valkey 9.