Skip to main content

Supabase

Supabase is an open-source backend platform that provides PostgreSQL database, authentication, real-time subscriptions, and serverless edge functions. It's a great fit for game backends that need managed auth, a relational database, and real-time capabilities without running a custom WebSocket server.

How It Works

GameFlow integrates with Supabase through Edge Functions — serverless TypeScript functions that run on Deno. One Edge Function acts as the bridge: when a lobby is ready to start, it calls the GameFlow API to allocate a dedicated game server, then writes the server's address and port back to the database. Supabase Realtime picks up the change and pushes the connection details to all players simultaneously.

┌──────────────┐    HTTP (Edge Functions)    ┌──────────────────────┐    GameFlow API     ┌──────────────────┐
│ Game Client │ ◄────────────────────────► │ Supabase │ ──────────────────►│ GameFlow │
│ │ Auth, lobby CRUD, │ Edge Functions │ POST /fleets/ │ Server Hosting │
│ │ ready state │ + PostgreSQL │ {id}/allocate │ │
└──────────────┘ └──────────────────────┘ │ └──────────────────┘
▲ │ { address, port } │
│ Supabase Realtime (WebSocket) │◄─────────────────────────────────────────┘
└───────────────────────────────────────────────┘
lobby updated → all clients connect to game server

The Flow

  1. Player signs in via Supabase Auth (anonymous or with a provider).
  2. Player creates or joins a lobby — Edge Functions write to PostgreSQL.
  3. All players mark ready. The lobby owner presses Start.
  4. The lobbies-start Edge Function validates readiness, then calls the GameFlow fleet allocation API.
  5. GameFlow returns address and port for the allocated server.
  6. The Edge Function writes the server details to the lobbies table.
  7. Supabase Realtime fires an UPDATE event to all subscribers.
  8. Every client in the lobby connects directly to the game server.

Key Integration Point

The only GameFlow-specific code in your backend is the server allocation call in your lobbies-start function:

const res = await fetch(
`https://dev.api.gameflow.gg/v1/fleets/${gameId}/allocate`,
{
method: "POST",
headers: { "X-Api-Key": apiKey },
body: JSON.stringify({
region: "us-east",
payload: JSON.stringify({ players }),
}),
}
);

const { allocation } = await res.json();

// Write back to DB, this triggers Supabase Realtime for all clients
await supabase.from("lobbies").update({
status: "started",
server_port: allocation.port,
server_address: allocation.address,
}).eq("id", lobby_id);

Client-Side Realtime

On the client, subscribe to the lobbies table. When status changes to started, the server address and port are immediately available:

const event = {
event: "UPDATE",
schema: "public",
table: "lobbies",
filter: `id=eq.${lobbyId}`,
}

const handler = (payload) => {
if (payload.new.status === "started") {
connectToGameServer(payload.new.server_address, payload.new.server_port);
}
}

supabase
.channel("lobby-updates")
.on("postgres_changes", event, handler)
.subscribe();

Deployment

Local development

supabase start
supabase functions serve --env-file supabase/functions/.env.local

Set your GameFlow credentials in supabase/functions/.env.local:

GAMEFLOW_GAME_ID=your-game-id
GAMEFLOW_API_KEY=your-api-key

Production

supabase link --project-ref <your-project-ref>
supabase db push
supabase functions deploy
supabase secrets set GAMEFLOW_GAME_ID=your-game-id
supabase secrets set GAMEFLOW_API_KEY=your-api-key

SUPABASE_URL and SUPABASE_ANON_KEY are injected automatically into Edge Functions — do not set them manually.

Sample Project

See the Godot + Supabase sample project for a complete, working implementation of this integration:

👉 Godot + Supabase Sample Project

It includes the full database schema, all Edge Functions, Godot client code, Agones SDK integration, and step-by-step setup instructions for both local development and production.