Skip to content
BlinkBlox

BlinkBlox

Describe your remotes in a schema. Get server and client modules that pack them into buffers, check everything a client sends, and hold up when a client is hostile.

You describe your events and functions, and what they carry, in a .blink file. The compiler turns that file into a server module and a client module. Both are plain Luau with no runtime dependency. Calls are batched into one buffer per frame, and each type is packed as tightly as its declaration allows.

Net.blink
option DefaultRate = 20
struct Hit {
Target: Instance(Humanoid),
Damage: u8(1..100),
Critical: boolean,
}
event Damage {
From: Client,
Type: Reliable,
Call: SingleSync,
Rate: 10,
Data: Hit
}
event Position {
From: Server,
Type: OrderedUnreliable,
Call: SingleSync,
Data: (Id: u16, Where: vector<f32>)
}
function GetInventory {
Yield: Coroutine,
Data: u32,
Return: string(0..32)[..64]
}

Safe to point at the internet

Packets are bounded before they are parsed. Each player gets a byte budget, and each event can get its own rate limit, each function a cap on the calls still running. Every length is checked before the read it pays for. A malformed event ends its packet without throwing, and the game is told who sent it. How the server protects itself.

Small on the wire

Booleans and optional flags share a bitfield, and boolean[] packs eight elements to a byte. A length is sent relative to its range, a rotation fits in 7 bytes, and 24-bit numbers make a position 9 bytes instead of 12. Unreliable events that cannot fit are refused at compile time. Bandwidth and sizes.

Checked at compile time

A schema that cannot work never builds. That covers map keys that can never be looked up, cyclic imports, unbounded decode loops and debug remotes left in a release build. Each gets a diagnostic with a code and a source span. Diagnostics.

Tooling included

The CLI has watch mode and build profiles, and --check --json hands every diagnostic to an editor or an AI assistant as JSON. A Studio plugin gives you an editor with live diagnostics and autocomplete, and TypeScript definitions are available for roblox-ts. Studio plugin.

BlinkBlox is a maintained fork of Blink. Upstream froze this line of the compiler in 2026 and began a rewrite, and it declared an unbounded parse of a hostile client buffer out of scope. This fork fixes that and continues from there, without giving up the TypeScript output, the Studio plugin or the documentation.

Buffer code written by hand is the other neighbour, and for a server’s own sends or a remote or two it is the simpler choice. What it leaves to you is the receiving side: every length, range and class a hostile client can get wrong, in every remote. Compared with hand-written buffers shows both readers for one event.

Zap is a neighbouring compiler that focuses on bandwidth. It leaves rate limiting to the game, and its decode loop has no pcall: one malformed event throws out of it, discarding the rest of that player’s batch with nothing for the game to catch.

QuickNet and Warp are libraries rather than compilers: a schema is declared at runtime and packed into buffers. QuickNet limits each event per player and bounds a packet’s size and its calls, and a pcall around each packet stops a malformed event from throwing, as BlinkBlox’s does. It only warns in the output rather than telling the game who sent it, and allocates whatever array length a client names before reading any of it. Warp counts a player’s bytes a packet at a time, outside Studio only, and reads lengths the client sends straight into table.create.

BlinkBlox Blink 0.18 Zap QuickNet 0.3 Warp 1.1
Per-player, per-event rate limits Yes No No Yes No
A decode failure is caught and reported to the game Yes No No Caught, not reported No
Shared bitfield for booleans and optionals Yes No Yes Boolean arrays only Optionals, boolean arrays
TypeScript output Yes Yes Yes No No

Speed is not the reason to choose BlinkBlox: a reader written by hand for one event can be as fast as anything generated for it. The numbers compare tools that do the same job, and hold each release to the one before it.

A thousand events a frame from client to server, run in Studio on an Intel Core i7-13700K on 0.41.2. Blink is upstream’s last release, 0.18.9. The numbers are median frame rates, with the milliseconds a frame’s thousand fires took in brackets. Warp’s Fire only queues its value and encodes it later in the frame, where the bench cannot time it, so only its frame rate is shown.

Tool 1000 booleans 1000 booleans, each different 100 entities 100 entities, each different
Roblox remotes 15 FPS (26.0 ms) 15 FPS (29.1 ms) 15 FPS (72.7 ms) 15 FPS (74.5 ms)
BlinkBlox 60 FPS* (1.9 ms) 60 FPS* (4.8 ms) 60 FPS* (2.0 ms) 60 FPS* (2.4 ms)
Blink 60 FPS* (4.5 ms) 60 FPS* (9.9 ms) 44 FPS (2.8 ms) 45 FPS (3.2 ms)
zap 60 FPS* (12.2 ms) 46 FPS (18.1 ms) 45 FPS (7.4 ms) 44 FPS (7.8 ms)
ByteNet 30 FPS (17.5 ms) 23 FPS (21.4 ms) 35 FPS (15.8 ms) 34 FPS (16.6 ms)
Packet 35 FPS (27.3 ms) 28 FPS (31.8 ms) 27 FPS (19.2 ms) 27 FPS (19.9 ms)
QuickNet 60 FPS* (1.9 ms) 60 FPS* (7.1 ms) 58 FPS (6.2 ms) 57 FPS (6.7 ms)
Warp 60 FPS* 55 FPS 33 FPS 32 FPS

* Studio caps the frame rate at 60. How these were measured.