Skip to content

Wire Protocol

Flo uses a custom binary protocol for client-server communication on port 9000. The protocol supports TLV (Type-Length-Value) encoding for efficiency and zero-copy parsing.

Clients connect via TCP to the server’s client port (default 9000). The first bytes sent identify the protocol:

Magic BytesProtocol
FLO\x01Binary wire protocol
*, $, +, -RESP (Redis protocol)
GET, POST, …HTTP (redirected to dashboard)
WebSocket upgradeWebSocket (binary protocol over WS frames)

The Acceptor thread peeks at the first bytes to detect the protocol and routes accordingly.

Every request has a fixed 32-byte header followed by a variable-length payload:

┌──────────────────────────────────────────────────────────────────┐
│ Request Header (32 bytes) │
├──────────┬──────────┬───────┬──────────┬──────────┬──────────────┤
│ magic │ opcode │ flags │ req_id │ payload │ namespace │
│ (4B) │ (2B) │ (2B) │ (8B) │ _len(4B) │ _hash (8B) │
├──────────┴──────────┴───────┴──────────┴──────────┴──────────────┤
│ key_length │ padding │
│ (2B) │ (2B) │
├────────────┴─────────────────────────────────────────────────────┤
│ Payload (variable) │
│ [key bytes] [value bytes] [optional TLV fields] │
└──────────────────────────────────────────────────────────────────┘
FieldTypeDescription
magicu32Protocol magic: 0x464C4F01 (“FLO\x01”)
opcodeu16Operation code (see OpCode table)
flagsu16Request flags (compression, etc.)
req_idu64Client-assigned request ID for response matching
payload_lenu32Length of payload following the header
namespace_hashu64FNV-1a hash of the namespace string
key_lengthu16Length of the key in the payload
┌──────────────────────────────────────────────────────────────────┐
│ Response Header (24 bytes) │
├──────────┬──────────┬───────┬──────────┬──────────────────────────┤
│ magic │ status │ flags │ req_id │ payload_len │
│ (4B) │ (2B) │ (2B) │ (8B) │ (4B) │
├──────────┴──────────┴───────┴──────────┴──────────────────────────┤
│ Payload (variable) │
└──────────────────────────────────────────────────────────────────┘
CodeNameDescription
0x00OKOperation succeeded
0x01NOT_FOUNDKey / queue / stream not found
0x02BAD_REQUESTInvalid request parameters
0x03CONFLICTCAS version mismatch
0x04UNAUTHORIZEDAuthentication required
0x05OVERLOADEDServer at capacity (retry)
0x06INTERNAL_ERRORServer error
0x07NOT_LEADERNode is not the leader for this partition

The protocol defines 167 operation codes organized by subsystem:

OpCodeValueDescription
kv_get0x10Get value by key
kv_put0x11Set key-value pair
kv_delete0x12Delete a key
kv_scan0x13Prefix scan
kv_batch_put0x14Batch put multiple keys
kv_history0x15Get version history
kv_cas0x16Compare-and-swap
OpCodeValueDescription
queue_enqueue0x20Add message to queue
queue_dequeue0x21Fetch and lease messages
queue_ack0x22Acknowledge messages
queue_nack0x23Negative acknowledge
queue_peek0x24Peek without leasing
queue_touch0x25Extend lease
queue_dlq_list0x26List DLQ messages
queue_dlq_requeue0x27Requeue from DLQ
OpCodeValueDescription
stream_append0x30Append record
stream_read0x31Read records
stream_create0x32Create stream
stream_info0x33Stream metadata
stream_trim0x34Trim old records
stream_group_create0x35Create consumer group
stream_group_read0x36Consumer group read
stream_group_ack0x37Consumer group ack
OpCodeValueDescription
ts_write0x40Write data point
ts_write_batch0x41Batch write points
ts_query0x42Execute FloQL query
ts_create_measurement0x43Create measurement
OpCodeValueDescription
action_register0x50Register action type
action_invoke0x51Invoke action
action_status0x52Get execution status
action_result0x53Get execution result
OpCodeValueDescription
worker_register0x60Register worker
worker_await0x61Await task assignment
worker_complete0x62Complete task
worker_fail0x63Fail task
worker_heartbeat0x64Worker heartbeat
worker_touch0x65Extend task lease
OpCodeValueDescription
cluster_join0xC0Join cluster
cluster_leave0xC1Leave cluster
cluster_status0xC2Cluster health
cluster_partition_table0xC3Get partition table

Some operations include optional TLV (Type-Length-Value) fields after the key and value:

┌──────┬────────┬───────────┐
│ type │ length │ value │
│ (1B) │ (2B) │ (var) │
└──────┴────────┴───────────┘
TypeNameUsed By
0x01TTLKV put
0x02CAS versionKV put/delete
0x03PriorityQueue enqueue
0x04DelayQueue enqueue
0x05Dedup keyQueue enqueue
0x06Block timeoutGet, dequeue, stream read
0x07Consumer groupStream group operations
0x08Idempotency keyAction invoke

Flo also accepts Redis RESP protocol on the same port. The Acceptor detects RESP by the leading character (*, $, +, -, :). RESP commands are translated to Flo operations:

RESP CommandFlo Operation
SET key valuekv_put
GET keykv_get
DEL keykv_delete
SCAN cursor MATCH patternkv_scan
LPUSH queue valuequeue_enqueue
RPOP queuequeue_dequeue
XADD stream * field valuestream_append
XREAD COUNT n STREAMS stream idstream_read

This allows Redis clients to connect to Flo without modification for basic operations.