Pigeon

Networking for Roblox that stays small as your game grows.

Pick a name on the server, pick the same name on the client, and the two are talking. Pigeon handles the remotes, the ordering, the startup race and the cleanup for you.

Names, not instances

You name a channel; Pigeon creates and wires the RemoteEvent behind it. Build the same name on both sides and they are connected.

A small pool of remotes

Hundreds of channels share at most 32 RemoteEvents. Add a feature and your instance count stays flat.

Channels you can lock

Put a guard on a channel and only players who pass it can send or receive. A staff channel is safe to shout on.

Tables that replicate

Change a table on the server and the clients holding it see the change. No manual sync code and no diffing.

No startup race

Anything sent before a client is ready waits in a queue. Register your handlers first, then let the backlog in.

Cleanup in one call

Group related channels and drop them all together. Nothing is left connected after you tear a system down.

The whole idea

Two files. One name. That is the entire setup.

Server
local Pigeon = require(ReplicatedStorage.Pigeon)

local shop = Pigeon.new("Shop")

shop:When("Buy", function(player, itemId)
	local ok = giveItem(player, itemId)
	return ok
end)

shop:Broadcast("StockChanged", getStock())
Client
local Pigeon = require(ReplicatedStorage.Pigeon)

local shop = Pigeon.new("Shop")

shop:On("StockChanged", function(stock)
	updateShopUi(stock)
end)

shop:Init()

print(shop:Call("Buy", "sword"))

No RemoteEvent was created, named, found or waited for. The name "Shop" is the only thing the two sides agree on.

Built on a good idea

Pigeon is heavily inspired by roblox-sockets by OMouta, which brought the socket style of events, rooms and middleware to Roblox. Go and look at it. Pigeon takes that shape and adds a shared remote pool, a startup queue, locked channels and replicated tables on top.

Read the credits