Multiplayer game backend architecture.
Latency is the product. Every architectural decision here is subordinate to keeping the round trip between a player and the simulation short.
The components
Every row below is read from the graph that produced the diagram above, so the two cannot disagree.
| Component | Tier | Why it is there |
|---|---|---|
| Game client | Client | Client-side prediction, server reconciles |
| Edge routing | Edge | Latency-based, region matters more than anything |
| Session gateway | Edge | Supporting component |
| Matchmaker | Application | Skill and latency buckets |
| Game servers | Application | Authoritative simulation, one per match |
| Fleet orchestrator | Application | Pre-warmed pool, cold start loses players |
| Player profile | Application | Supporting component |
| Leaderboard | Application | Supporting component |
| Redis | Data | Sorted sets for ranks |
| Postgres | Data | Supporting component |
| Kafka | Data | Supporting component |
Design decisions worth arguing about
A diagram shows what was chosen. It does not show what it cost, and that is usually the part that matters in a review or an interview.
The server is authoritative, the client predicts
Trusting the client is trusting cheaters, so the server simulates and its result wins. That introduces the round trip as visible input lag, which clients hide by predicting locally and reconciling when the server disagrees. Reconciliation is what produces rubber-banding, and it is the honest cost of not letting players decide whether they hit each other.
Match on latency as well as skill
A perfectly skill-matched game across a high-latency link is a worse experience than a slightly mismatched local one. Bucketing by both means the matchmaker balances two objectives that conflict at low population, and the resolution is always the same: relax skill before relaxing latency, because players forgive a hard game more readily than a laggy one.
Pre-warm the fleet, because cold start is visible
Starting a container when a match is ready adds seconds during which players sit watching a spinner, and some of them leave. Keeping a warm pool absorbs that, at the cost of paying for idle capacity sized to peak concurrency. This is a straightforward money-for-experience trade and the amount is a business decision rather than a technical one.
UDP for the simulation, TCP for everything else
Game state is fine to lose, because a newer update supersedes it, and TCP's retransmission of stale data actively hurts. Sessions, profiles and purchases must not be lost. Running two transports means two networking paths, two sets of firewall problems and two failure modes, which is why this is worth it only for the traffic that is genuinely latency-critical.
How it changes with scale
Capacity is concurrent matches, and each match is an independent process, so scaling is close to embarrassingly parallel. Regional distribution is mandatory rather than an optimisation, since latency is geography. The stateful part is small: profiles and leaderboards, both of which are ordinary services.
Where it breaks first
A game server crashing mid-match. The simulation is authoritative and in memory, so the match state is gone. Players see a disconnect and the outcome is ambiguous, which is worse than a loss. Periodic state snapshots let a replacement resume rather than abandon, and the decision of how often to snapshot is a direct trade against simulation performance.
Draw this yourself
Open the Diagram tab and describe the system. The agent emits a semantic graph rather than coordinates, so you can edit the components and the layout re-solves instead of drifting.
When the shape is right, Implement in code turns the canvas into a markdown specification, every component, every relationship and the notes, and starts a real turn in the Code tab with it.
Questions about this design
Dedicated servers or peer-to-peer?
Dedicated for anything competitive: peer-to-peer makes one player the authority, which is a cheating vector and a connection-quality lottery. Peer-to-peer remains reasonable for cooperative play among friends.
How do you prevent cheating?
Server authority for anything that affects outcomes, plus anomaly detection on the event stream. Client-side anti-cheat is an arms race that the server-authoritative design mostly renders unnecessary for the important cases.
How should the matchmaker handle low population?
Widen the acceptable ranges over time and be explicit with the player about the wait. Matching them into a badly balanced game silently is how a low-population game loses the players it still has.
Why Redis for leaderboards?
Sorted sets give ranked insert and range query directly, which is precisely the operation, and leaderboard state is reconstructible from the event stream if lost.
More templates
- Multi-Tenant SaaS ArchitectureOne database serving every customer, and exactly one bug standing between that and showing one customer another customer's data.
- Data Warehouse ETL Pipeline DesignLand the raw data first and transform it later, because the transformation you want in six months is not the one you would write today.
- IoT Telemetry Platform DesignAssume every device is offline, on a bad network, running firmware from two years ago, and cannot be recalled. The architecture follows from that.
- API Gateway System DesignOne entry point, so authentication, rate limiting and observability are implemented once instead of in every service.
Last updated