Skip to main content
A flushed buffer contains one or more packets laid end to end. There is no outer header and no packet count, because the receiver simply loops until the cursor reaches the end of the buffer.

Packet layout

Every packet has the same three-part shape, read in this order:
varint-prefixed string
The event name you passed to Flux.Server or Flux.Client, written with WriteString. This is what the dispatcher keys listener lookup on, so it is repeated in every packet. Keep names short if you send at very high frequency.
1 byte, or 1 plus a varint
A packed byte holding the packet type and the argument count. See below.
argCount values
Encoded either by the event’s schema or by the dynamic encoder, depending on packet type and whether a schema is registered.

The header byte

The two-bit packet type sits in the high bits and the argument count in the low six.
Bit 7 is the most significant. The type occupies the top two bits because it is written as packetType << 6, so a header for an event with two arguments is 0x42: 01 in the high bits, 000010 in the low six.
63 is an escape value, not a count. Counts of 0 to 62 fit in the header byte directly; a count of 63 or more writes 63 in the field and follows it with a varint carrying the real count. So the header is one byte for essentially all real traffic.

Packet types

Only two bits are allocated, so the format has room for one more packet type (0 is unused). Values outside 1 to 3 are ignored by both dispatchers rather than raising an error.

EVENT

The payload is the arguments you passed to Fire, in order.
If a schema is registered for the name, each argument is encoded with schema[i]. Otherwise each is tagged and encoded by WriteAny.

REQUEST

Sent by Client:Invoke. The first payload value is the request id, followed by the invoke arguments.
The request id is a plain incrementing counter kept per channel name on the client. It is written with WriteAny, so a fresh session’s early requests cost one tag plus one byte.

RESPONSE

Sent by the server after OnInvoke returns. The first two payload values are the request id and a success flag, followed by the handler’s return values.
number
Echoed back from the request so the client can find the parked thread.
boolean
The first result of the server’s pcall. When false, the next value is the error message and Invoke re-raises it.
The client accepts true or 1 as success when reading the flag, so the encoding tolerates the boolean arriving as a narrowed integer.

A worked example

Two events fired to the same player in one frame:
They share one writer, so a single FireClient carries both packets back to back:
Note how much of that is the channel names: 12 of 21 bytes. At high frequency, shortening "PlayerPositionUpdate" to "P" is a real saving, and one no schema can give you.

Next steps

Type tags

Every dynamic-encoder tag and its cost.

Buffers API

The read and write primitives behind the format.