Wire Protocol
Layering
Section titled “Layering”The transport crate is the shared source of truth for client and server communication.
Flow:
Request -> transport encode -> TCP/TLS bytes -> transport decode -> Response
Protocol Version
Section titled “Protocol Version”Current protocol:
- magic:
VTP2 - version:
2
0.2.x+ intentionally rejects pre-v2 frames. 0.1.0 clients and servers are not wire-compatible with 0.2.0+.
Within protocol v2, 0.3.0 changes successful EXEC responses from a lossy string list to a structured typed payload. 0.2.x transaction clients that assume EXEC decodes as Response::strings(...) are not wire-compatible with 0.3.0 servers for transaction result decoding.
0.8.0 keeps protocol version 2 but hardens value semantics and request
encoding:
- value-bearing request fields are binary-safe length-prefixed byte payloads
- value-bearing response fields are binary-safe length-prefixed byte payloads
SETnow carries an optionalif_version: u64tail for version-based CAS
Startup Negotiation
Section titled “Startup Negotiation”Each connection begins with a required startup hello before command frames.
Client hello fields include:
- protocol version
- client name/version
- supported capabilities
- desired compression mode
- maximum frame size
- auth intent
Server hello fields include:
- accepted protocol version
- selected capabilities
- selected compression mode
- effective maximum frame size
- server ID
- structured rejection details when negotiation fails
Current negotiated capabilities:
zstdrequest_deadlineserver_metricspipeliningtrace_context
Frame Header
Section titled “Frame Header”Each frame carries:
| Field | Type | Purpose |
|---|---|---|
magic | u32 | Protocol identification |
version | u8 | Wire version |
flags | u8 | Per-frame behavior flags |
length | u32 | Payload byte length |
checksum | u32 | CRC32 of the transmitted payload bytes |
Current header length: 14 bytes.
Request and Response Bodies
Section titled “Request and Response Bodies”Requests contain:
request_id: UUIDopcode- optional metadata:
- deadline milliseconds
- trace ID
- sequence number
- request payload
Responses contain:
request_id: UUID- status
- response payload
Most responses use the same payload families as 0.2.x, but successful EXEC
responses now use a dedicated typed result payload rather than flattened
strings. In 0.8.0, value-bearing payloads are opaque bytes rather than
implicitly UTF-8 strings.
Request IDs and Pipelining
Section titled “Request IDs and Pipelining”Request IDs are UUIDs. They allow response correlation across pipelined requests on one connection.
Transaction constraint:
- while a transaction is active on a connection, sequence-tagged or pipelined requests are rejected
Compression
Section titled “Compression”Current outbound compression behavior:
- zstd is enabled by default for outbound frames in the server and client binaries
- compression is selected during startup negotiation
--disable-compressiondisables outbound compression on that process- URL query
compression=none|zstdconfigures the client - large async zstd compression and decompression are offloaded away from network hot paths
Compression is frame-level, not payload-field-level. The checksum covers the compressed bytes that were actually transmitted.
Status Codes
Section titled “Status Codes”| Status | Meaning |
|---|---|
Ok | Successful request |
Error | Structured remote error payload |
NotFound | Missing value / key |
Remote Errors
Section titled “Remote Errors”Remote failures are structured rather than ad hoc strings:
- stable code
- friendly name
- message
That makes the protocol safer for clients, tooling, and future SDKs.
Structured EXEC Results
Section titled “Structured EXEC Results”Successful EXEC responses are now encoded as a typed result list.
Shape:
u32 result_count- repeated
result_counttimes:u8 result_kind- kind-specific payload
Current result kinds:
| Kind | Meaning |
|---|---|
0x00 | ok |
0x01 | not_found |
0x02 | byte value |
0x03 | boolean |
0x04 | count (u64) |
0x05 | integer (i64) |
0x06 | entry list with byte values |
0x07 | optional byte value list |
0x08 | scan payload |
This fixes the old transaction result ambiguity where values like "true",
"42", or "NOT_FOUND" could not be reliably distinguished from real string
data after stringification, and in 0.8.0 it preserves exact byte payloads.
Current Opcode Surface
Section titled “Current Opcode Surface”Current wire opcodes cover:
- auth and ping
- binary-safe key/value reads and writes
- numeric operations
- TTL commands
- rename and scan
- info and metrics
- logical backup/restore
- maintenance mode
- health, cluster, and replication inspection
- cluster membership controls
- replication promotion/pause/resume controls
- user/role/permission management
- transaction controls
The transport itself remains protocol version 2; the 0.3.0 EXEC payload
change, the 0.5.0 HA command additions, and the 0.8.0 binary-value / CAS
payload changes are contract extensions within VTP2, not a new protocol
version.
0.5.0 cluster and replication opcodes:
| Opcode | Meaning |
|---|---|
0x3A | health |
0x3B | show cluster |
0x3C | cluster join |
0x3D | cluster remove |
0x3E | show replication |
0x3F | promote follower |
0x40 | pause replication |
0x41 | resume replication |
0x46 | internal replication vote |
0x47 | internal replication heartbeat |
0x48 | internal replication append |
0x49 | internal replication snapshot install |
For exact user-facing syntax, use Command Reference.