in_game with the same matchId and the same server connection info.
The Full Flow
Host starts matchmaking
POST /v3/lobbies/{config}/me/matchmaking with a mode name.Lobby status → in_queue. matchmaking.mode populates. Queue stats begin streaming via SSE.System searches for compatible lobbies
Other lobbies in the same config + mode are evaluated. Rules applied (MMR, region, party size). Candidates sorted by wait time.
Game server launches
One dedicated server starts. All matched lobbies get the same
matchId and server.ports[].Configuring Matchmaking
Matchmaking modes are defined in your lobby config in the PlayFlow dashboard. Each config can have multiple modes:No config? No problem. If you don’t set up matchmaking in the dashboard, the
/me/matchmaking endpoint returns a 400 asking you to configure modes. All lobby operations still work without config (they use defaults).Starting Matchmaking
in_queue with queue stats:
When a Match Is Found
When the system matches your lobby with others, the SSE stream emits an update:matchId and same server. Clients connect to server.ports[0].host:port.
Cancel Matchmaking
waiting.
Team Modes
Symmetric Teams (Traditional)
Most competitive games. N teams of M players, everyone equal.teams— how many teams to formplayersPerTeam— target size (matchmaker tries to fill to this)minPlayersPerTeam— minimum required to start (for partial matches)
| Mode | Config |
|---|---|
| 1v1 ranked | teams: 2, playersPerTeam: 1 |
| 2v2 duos | teams: 2, playersPerTeam: 2 |
| 5v5 competitive | teams: 2, playersPerTeam: 5 |
| 100-player FFA | teams: 1, playersPerTeam: 100, minPlayersPerTeam: 20 |
| 50-squad battle royale | teams: 50, playersPerTeam: 2, minTeams: 10 |
Asymmetric Teams (Role-Based)
For games like Dead by Daylight (1 killer vs 4 survivors) or Evolve (1 monster vs 4 hunters):state.role:
- Places players with the most specific role first (
bossbeforefill) - Keeps party members together on the same team
- Uses
"fill"as a wildcard (assigns wherever there’s an open slot) - Excludes spectators (or any role in
excludedFromQueue)
Skill-Based Matchmaking
Add matchmaking rules to filter candidates by player attributes:|lobbyA.{field} - lobbyB.{field}| <= maxDifference.
Lobby state is automatically averaged across eligible players to compute each lobby’s value. So if a party has players with MMR 1400 and 1600, the lobby’s MMR is 1500.
Auto-Expanding Buckets
The hardest part of skill matchmaking is balancing quality vs wait time. PlayFlow handles this automatically:As players wait longer, the acceptable range grows.Formula:
effectiveMax = maxDifference × (1 + longestWaitTime / modeTimeout)
Using maxDifference: 100, timeout: 60s:
| Wait time | Effective range |
|---|---|
| 0s | ±100 MMR (strict) |
| 15s | ±125 MMR |
| 30s | ±150 MMR |
| 60s | ±200 MMR |
| 120s | ±300 MMR |
maxDifference and timeout — the expansion is derived. This is how every competitive matchmaker (Riot, Valve, Blizzard) works — they just never made you configure it.
Multiple Rules
Add multiple rules and all must pass:Region Matching
Players specify their acceptable regions in state (or PlayFlow falls back to the lobby’s region):- Intersects all matched lobbies’ region lists
- Within the intersection, counts weighted votes (1/(index+1) by preference order)
- Picks the highest-voted region for the server
Queue Stats
While inin_queue, your lobby response includes live queue stats:
Backfill
For long-running persistent games (e.g., battle royale with late-join):Party Size Limits
Prevent a 5-stack from queueing for a 1v1:maxPartySize eligible players are rejected from queueing.
How Matchmaking Runs
Matchmaking runs inline on queue entry. When lobby B calls
POST /me/matchmaking, the system immediately scans for compatible lobbies. If A is already queued, B matches with A within ~100ms. No polling loops, no worker delay.A QStash-driven cron runs every 60s as a safety net (catches edge cases like simultaneous-entry races).FOR UPDATE SKIP LOCKED + a claim-then-create pattern. Two simultaneous match attempts can never claim the same lobbies or launch duplicate servers.
Error Cases
| Status | Cause |
|---|---|
400 Mode not found | The mode you passed isn’t defined in your lobby config |
400 Party size exceeded | Your lobby has more players than maxPartySize |
400 Already in queue | Lobby is already in in_queue status |
403 Not host | Non-host tried to start/cancel matchmaking |
409 Invalid state | Lobby is in_game or otherwise not in waiting |
Full Example: Ranked 1v1
Real-time Events
Stream matchmaking progress and queue stats via SSE.
API Reference
Full schemas for the matchmaking endpoints.