Sharding a project
Every project starts on one server, shard 0. Sharding runs a project on up to four servers instead, numbered from 0. A room lives on exactly one shard for its whole life, and irtio keeps a directory of which room is on which shard, so your client code and your room code do not need to know shards exist.
When to split
Split when one server is genuinely full, not because a single room is busy. The signs:
- A room type’s
maxAwakeis reached and new rooms of that type are refused withE_TYPE_AT_CAPACITY. See limits for howmaxAwakesizes a server. - The server is running close to its memory ceiling under real load, as reported on the dashboard’s Metrics page.
A hub or singleton room, one that many players talk to through the room bus, is not a reason to split. That room still runs on one shard no matter how many shards the project has. Sharding spreads independent rooms across servers, it does not divide one room’s work. If your project’s load is one busy hub and not much else, sharding will not help it.
How to split
POST /v1/projects/:id/shards
{ "shards": 3 } Owner authentication is required. shards is 2 to 4, and it can only go up: this call cannot lower
a project’s shard count today. Refusals are all 409, each with a reason:
| Reason | Message |
|---|---|
shards is lower than the project’s current count | removing a shard needs its rooms rehomed, which is not built |
| The org’s plan is not the card plan | sharding is a card-plan feature |
| The project is relay-only, no room code deployed | relay projects have no server to shard |
| No server in the project’s region can run another shard yet | wait for the region to be upgraded, or ask the operator |
The request fails with 400 when shards is above 4 or is not a whole number, before any of the 409 checks above run.
On success, every running shard of the project is stopped before the call answers. The shard count
is written next, and the project cold-boots the next time it starts: every shard, not only the new
ones, because the shard count is part of each server’s boot environment. This is the same disruption
as a deploy that changes memoryMb or maxAwake, and it happens again on every later increase, not
only the first one. Rooms restore from their snapshots as they do after any other cold boot.
GET /v1/projects/:id reports shards on the project. irtio status prints a shards: n line.
Per-shard status lines are not built yet.
What changes and what does not
Splitting a project does not change what a room can do. Room state, saves, player KV, alarms, leaderboards, ratings and quick-match all work exactly as they do on one shard: they are keyed by project and room, not by shard.
irtio keeps the room directory. Rooms a running shard reports are entered into it as they are seen, so a room never moves. A report that contradicts the directory is logged and counted, and the directory wins.
What sharding changes is where a room runs:
- A room that existed before the project was split stays on shard 0.
- A new room goes to the project’s newest shard.
- A deploy reaches every running shard, in shard order. A
migratedeploy that reaches some shards and not others is reported as a502naming the shard that refused. Run the same command again to retry. A retry only touches the shards that still need it, so it is safe to run more than once. - A rollback stops every shard.
The room bus across shards
room.bus.send still reaches any room in your project, whichever shard it is on. Same shard,
nothing changes. On a different shard, the message is held in the sending room’s own outbox,
forwarded by irtio, and delivered on the target shard. If the target’s shard is not running, irtio
starts it and the message delivers on retry. The promise you get back resolves the same way it does
on one shard: it succeeds, or it rejects with E_BUS_NO_SUCH_ROOM or E_BUS_MAILBOX_FULL. Retries
run on the sending room’s record, not in its handler, so a sender that has gone to sleep is not
woken and not billed for its own outbox. A message can also arrive twice when the retry fires while
the target is still loading the room. That is the same duplicate as a lost acknowledgement, and the
same rule applies.
room.bus.publish reaches subscribers on the same shard only. It does not cross shards yet. See what is not built yet below.
See the room bus for the full guarantees, including why a handler has to
tolerate seeing the same send twice.
Limits per server
A sharded project has more servers, and several limits are enforced per server rather than per project:
- New connections per IP per minute, and the
HELLOrate limit, are both per server. - The free tier’s awake-rooms limit is per server.
maxAwakefor a room type is per server: it is what sizes that server, and it stays that way whether the project has one shard or four.
Sharding itself is a card-plan feature. If an org later drops to the free plan while a project is still sharded, the free-tier walls apply per shard, not divided across them. A four-shard project on the free plan gets four servers’ worth of free-tier room, not one.
Client ids stay unique within a room, exactly as on one shard. Sharding does not change that.
When the region is full
Sharding needs a server in the project’s region with room for another shard. If there is none, a
join for a project whose server is not up fails with E_PLACEMENT, naming the region. The client
does not retry this on its own. The fix is a server added to that region, or more capacity on one
already there. Joins to a server that is already up are unaffected. See the error reference for the full behavior.
What is not built yet
- Shard removal or room rehoming.
shardscan only increase. There is no way to lower a project’s shard count or move a room off the shard it landed on. - Automatic splitting. A project’s shard count only changes when you call the split route. Nothing raises it for you when a shard fills up.
- Cross-shard
publish.room.bus.publishonly reaches subscribers on the sending room’s own shard. Fanning a publish out to every shard is a later addition.