Custom Game Backend
GameFlow makes it easy to integrate custom-built backends with your game servers. A custom backend sits between your game client and GameFlow's infrastructure — it handles player authentication, lobby management, and calls the GameFlow API to allocate dedicated servers when a match is ready to start.
Why a Custom Backend?
While GameFlow handles server hosting, scaling, and matchmaking infrastructure, many games need their own backend logic for:
- Player authentication (Discord OAuth, anonymous login, Steam, etc.)
- Lobby systems (creating, joining, team assignment, ready checks)
- Real-time communication (WebSocket-based updates to connected clients)
- Game-specific logic (leaderboards, inventories, progression)
Your custom backend is the orchestrator: it manages game state on your terms, and when it's time to play, it requests a dedicated server from GameFlow via a single API call.
How It Works
┌───────────────┐ WebSocket / REST ┌──────────────────┐ GameFlow API ┌──────────────────┐
│ Game Client │ ◄──────────────────────────► │ Custom Backend │ ───────────────────────►│ GameFlow │
│ (Unreal, │ Auth, lobby, ready state │ (Deno, Node, │ POST /games/{id}/ │ Server Hosting │
│ Unity, etc.) │ │ Go, Python…) │ servers │ │
└───────────────┘ └──────────────────┘ ▲ └──────────────────┘
│ │
│ { address, port, │
│ serverName } │
└───────────────────────────┘
The flow:
- Players connect to your backend via WebSocket and authenticate.
- Players create/join lobbies, pick teams, and toggle ready status — all managed by your backend.
- The lobby owner starts the match. Your backend validates that all players are ready.
- Your backend calls the GameFlow API to allocate a dedicated game server, passing a payload with match data (players, teams, etc.).
- GameFlow spins up a server and returns the connection details (address + port).
- Your backend broadcasts the server details to all players in the lobby via WebSocket.
- Players connect directly to the game server and play.
GameFlow API Integration
The only GameFlow-specific code in your backend is the server allocation call. This is a single POST request that works from any language.
Endpoint
POST https://api.gameflow.gg/v1/games/{gameId}/servers
Headers
| Header | Value |
|---|---|
X-Api-Key | Your GameFlow API key |
Request Body
{
"region": "us-east",
"payload": `{"players":["id1","id2"],"teamA":[...],"teamB":[...]}`
}
| Field | Type | Description |
|---|---|---|
region | string | Target deployment region (e.g. us-east, eu-west). |
payload | string | An arbitrary JSON string that gets forwarded to your game server on startup. Use this to pass match context like player lists, team compositions, game mode, map selection, etc. |
Response
{
"server": {
"name": "server-abc123",
"address": "123.45.67.89",
"port": 7777
}
}
Your backend then forwards address and port to the game clients so they can connect directly to the dedicated server.
Example in Any Language
- TypeScript / JavaScript
- Python
- Go
- C# (.NET)
const response = await fetch(
`https://api.gameflow.gg/v1/games/${gameId}/servers`,
{
method: "POST",
headers: { "X-Api-Key": apiKey },
body: JSON.stringify({
region: "us-east",
payload: JSON.stringify({ players, teamA, teamB }),
}),
}
);
const { server } = await response.json();
// server.address, server.port, server.name
import requests, json
response = requests.post(
f"https://api.gameflow.gg/v1/games/{game_id}/servers",
headers={"X-Api-Key": api_key},
json={
"region": "us-east",
"payload": json.dumps({"players": players, "teamA": team_a, "teamB": team_b}),
},
)
server = response.json()["server"]
# server["address"], server["port"], server["name"]
body, _ := json.Marshal(map[string]interface{}{
"region": "us-east",
"payload": payloadJSON,
})
req, _ := http.NewRequest("POST",
fmt.Sprintf("https://api.gameflow.gg/v1/games/%s/servers", gameID),
bytes.NewReader(body))
req.Header.Set("X-Api-Key", apiKey)
resp, _ := http.DefaultClient.Do(req)
var client = new HttpClient();
client.DefaultRequestHeaders.Add("X-Api-Key", apiKey);
var body = JsonSerializer.Serialize(new {
region = "us-east",
payload = JsonSerializer.Serialize(new { players, teamA, teamB })
});
var response = await client.PostAsync(
$"https://api.gameflow.gg/v1/games/{gameId}/servers",
new StringContent(body, Encoding.UTF8, "application/json"));
var result = await response.Content.ReadFromJsonAsync<ServerResponse>();
// result.Server.Address, result.Server.Port
Example Implementation (Deno Template)
We provide a ready-to-deploy template built with Deno that implements a complete game backend with GameFlow integration. It's designed to get you up and running with minimal backend experience.
Repository: github.com/GameFlowGG/custom-game-backend
Tech Stack
| Technology | Purpose |
|---|---|
| Deno | Modern JavaScript/TypeScript runtime with built-in tooling — no node_modules, no bundler config |
| SQLite | Persistent account storage (players, Discord links) |
| Deno KV | Key-value store for ephemeral data (lobbies, sessions) |
| WebSockets | Real-time communication between clients and backend |
| JWT | Stateless authentication tokens |
Features
- Authentication: Discord OAuth and anonymous login. Returns a JWT that clients use for all subsequent requests and the WebSocket connection.
- Lobby System: Create/join lobbies (public or private with invite codes), team assignment (auto-balance or manual), ready checks, and bot fill for testing.
- Real-time Updates: All lobby state changes are pushed to connected clients via WebSocket pub/sub — no polling required.
- Match Start → Server Allocation: When the lobby owner starts a match, the backend validates readiness, calls the GameFlow API with a payload containing teams and player info, and broadcasts the allocated server's
addressandportto all players.
Setup
-
Clone the template:
git clone https://github.com/GameFlowGG/custom-game-backend.git
cd custom-game-backend -
Configure environment variables:
cp .env.example .envPORT=3000
JWT_SECRET=your-secret-key
GAMEFLOW_GAME_ID=your-game-id
GAMEFLOW_API_KEY=your-api-keyGet your
GAMEFLOW_GAME_IDandGAMEFLOW_API_KEYfrom the GameFlow Dashboard. -
Run locally:
deno task dev
Deploy
The fastest way to deploy is with Deno Deploy — click the button below to deploy directly from the template repo:
Or deploy via CLI:
deno install -Arf https://deno.land/x/deploy/deployctl.ts
deployctl deploy --project=your-project main.ts
Set your environment variables (JWT_SECRET, GAMEFLOW_GAME_ID, GAMEFLOW_API_KEY) in the Deno Deploy dashboard after deploying.
Building Your Own Backend
If you prefer a different language or framework, you only need to implement these pieces:
1. Authentication
Issue tokens (JWT or session-based) so your game client can identify players. The template uses Discord OAuth and anonymous login, but you can use Steam, Epic, or any provider.
2. Lobby / Matchmaking State
Track which players are grouped together and ready to play. This can be in-memory, Redis, a database, or a KV store — whatever fits your stack.
3. Real-time Communication
Use WebSockets (or any real-time transport) to push lobby updates and match-start events to connected clients. The game client needs to receive the server address and port to connect.
4. GameFlow Server Allocation
When a match is ready, make a single POST request to the GameFlow API (see GameFlow API Integration above). Pass any match context in the payload field — your game server will receive it on startup.
5. Broadcast Server Details
Once GameFlow returns the server's address and port, send them to all players in the match. Clients use these to connect directly to the dedicated game server.
That's it. GameFlow handles provisioning, scaling, and hosting the game servers — your backend just needs to tell it when to spin one up and relay the connection info back to players.