The Complete Guide to Real-time Multiplayer Games on Serverless
How to build multiplayer browser games using serverless architecture. Covers game state sync, player presence, turn-based and real-time patterns with practical code examples.
Building multiplayer games traditionally means running dedicated game servers 24/7, managing socket connections, and handling all the complexity of real-time synchronization.
But what if you could build multiplayer games using the same serverless architecture you use for your web apps? No servers to manage, pay only for what you use, and scale automatically from 2 players to 2,000.
This guide covers everything you need to know about building multiplayer games on serverless platforms like Vercel and Cloudflare Workers.
The Architecture
Multiplayer games on serverless use a different architecture than traditional game servers — for a deeper look at why, see why serverless can't hold WebSocket connections. The key insight: separate the WebSocket connections from the game logic, using a serverless WebSocket service to handle the persistent connections.
- PushFlo (or similar) handles the WebSocket connections
- Your serverless functions handle game logic
- A database (Redis, DynamoDB, Supabase) stores game state
What Types of Games Work on Serverless?
Great Fit
- Turn-based games — Chess, card games, word games
- Casual multiplayer — Trivia, drawing games, party games
- Slow-paced real-time — Tower defense, idle games, tycoons
- Social games — Chat-based games, werewolf, mafia
Challenging but Possible
- Fast-paced real-time — Shooters, racing (requires careful optimization)
- Physics-based — Depends on complexity and update rate
Not Ideal
- Twitch shooters — Sub-16ms requirements are hard to meet
- Large-scale MMOs — Sheer volume of state updates
This guide focuses on turn-based and casual real-time games, which cover 90% of indie multiplayer projects.
Building a Multiplayer Game: Step by Step
Let's build a real-time multiplayer Tic-Tac-Toe game. Simple enough to understand, but the patterns apply to any game.
Step 1: Define the Game State
// types/game.ts
interface GameState {
id: string;
board: (string | null)[]; // 9 cells: 'X', 'O', or null
players: {
X: string; // player ID
O: string | null; // null if waiting for opponent
};
currentTurn: 'X' | 'O';
status: 'waiting' | 'playing' | 'finished';
winner: 'X' | 'O' | 'draw' | null;
createdAt: string;
updatedAt: string;
}
Step 2: Create the Game Logic (Pure Functions)
// lib/game-logic.ts
export function createGame(playerId: string): GameState {
return {
id: generateId(),
board: Array(9).fill(null),
players: { X: playerId, O: null },
currentTurn: 'X',
status: 'waiting',
winner: null,
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
};
}
export function makeMove(
game: GameState,
playerId: string,
position: number
): GameState {
// Validate and apply move...
// Check for winner...
return updatedGame;
}
Step 3: Real-time Updates with PushFlo
// lib/realtime.ts
export async function publishGameUpdate(game: GameState) {
await fetch('https://api.pushflo.dev/api/v1/publish', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${process.env.PUSHFLO_SECRET_KEY}`,
},
body: JSON.stringify({
channel: `game-${game.id}`,
event: 'update',
data: game,
}),
});
}
Step 4: Client-Side Game Component
// components/TicTacToe.tsx
'use client';
import { useState, useEffect } from 'react';
import { PushFloClient } from '@pushflodev/sdk';
export function TicTacToe({ gameId, playerId }: Props) {
const [game, setGame] = useState<GameState | null>(null);
useEffect(() => {
// Fetch initial state
fetch(`/api/games/${gameId}`)
.then(res => res.json())
.then(setGame);
// Subscribe to updates
const client = new PushFloClient({
publishKey: process.env.NEXT_PUBLIC_PUSHFLO_PUBLISH_KEY!,
});
client.subscribe(`game-${gameId}`, {
onMessage: (updatedGame: GameState) => {
setGame(updatedGame);
},
});
client.connect();
return () => client.disconnect();
}, [gameId]);
const makeMove = async (position: number) => {
// Send move to server
await fetch(`/api/games/${gameId}/move`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ playerId, position }),
});
};
// Render game board...
}
Advanced Patterns
Pattern 1: Optimistic Updates with Reconciliation
For responsive gameplay, update the UI immediately and reconcile with server state.
Pattern 2: Player Presence
Show who's in the game room using presence channels.
Pattern 3: Game Timers
For timed turns, use server-authoritative timers.
Pattern 4: Matchmaking Queue
For games with matchmaking, implement a queue system.
Database Options
| Database | Best For | Latency | Cost |
|---|---|---|---|
| Vercel KV (Redis) | Fast reads/writes | <10ms | $ |
| Supabase | Postgres + Realtime | <50ms | $ |
| PlanetScale | MySQL, scaling | <50ms | $$ |
| DynamoDB | AWS ecosystem | <20ms | $$ |
Conclusion
Building multiplayer games on serverless is absolutely viable for:
- Turn-based games
- Casual real-time games
- Social/party games
- Games with <100ms latency requirements
The architecture is simpler than traditional game servers:
- No servers to manage
- No scaling to worry about
- Pay only for actual usage
- Deploy alongside your web app
The key is separating concerns: let PushFlo handle WebSocket connections, your serverless functions handle game logic, and your database handle state.
Ready to build your multiplayer game? Start with PushFlo free — perfect for game prototypes and indie projects.
Build your multiplayer game today
PushFlo is perfect for game prototypes and indie projects — start free.
Related Articles
Do You Really Need Millions of Messages? The Real-time Pricing Trap
Why most real-time services sell you quotas you'll never use. A honest look at what indie developers actually need from WebSocket infrastructure.
How to Add Real-time Features to Next.js Without Managing Servers
Learn how to add WebSocket-powered real-time features like live notifications, chat, and dashboards to your Next.js app deployed on Vercel — without running your own WebSocket server.
WebSocket Alternatives for Vercel and Cloudflare Workers
Vercel and Cloudflare Workers don't support WebSockets natively. Here are your options for adding real-time features to serverless apps, from polling to managed services.
