Skip to main content

Room

JavaScriptDartSwiftKotlinJavaUnityUnrealReact Native

EdgeBase Room is a server-authoritative real-time state synchronization primitive for multiplayer applications. Clients send actions, the server validates and mutates state, and all connected clients receive only the changed parts (deltas) automatically. Ideal for multiplayer games, collaborative editors, live dashboards, voting systems, and auctions — anything where consistency and trust matter.


What is Room?

Room is a real-time state synchronization primitive where the server has full authority over all state changes. Unlike traditional pub/sub (Realtime subscriptions, broadcast), Room doesn't just relay messages — it owns the state and enforces the rules.

Clients can only do two things: read state and send actions. The server validates every action, updates state, and automatically broadcasts only the changed parts (deltas) to connected clients.

This makes Room ideal for anything where consistency and trust matter:

  • Multiplayer games — lobbies, turn-based, real-time
  • Collaborative editors — shared documents, whiteboards
  • Live dashboards — real-time metrics, leaderboards
  • Voting / polls — tamper-proof state
  • Auctions — server-enforced bidding rules

How is it different from Realtime?

Realtime (pub/sub)Room
Who controls state?Clients write directlyServer only
ValidationClient-side or access rulesServer-side onAction handlers
StateNo built-in state3 state areas (shared / player / server)
Delta syncManualAutomatic — only changed fields are sent
Best forNotifications, presence, chatGames, collaboration, anything needing trust

Choosing Room vs the Other Realtime Features

Choose Room only when the server must own state and validate client actions. If you mainly need database change feeds, online indicators, or lightweight pub/sub, use Realtime primitives instead. If you need delivery to devices outside the active app session, use Push.

For the full five-way comparison, see Choosing Between Subscriptions, Presence, Broadcast, Room, and Push.


How it Works

Action Flow
Client A ── send('INCREMENT') ──▶  Server
                                   │  onAction['INCREMENT'] runs
                                   │  setSharedState(s => ({ ...s, count: s.count + 1 }))
Client A ◀── action_result ─────────│
Client A ◀── shared_delta ──────────│
Client B ◀── shared_delta ──────────│  (auto-broadcast to all)
  1. Client sends an action (type + payload)
  2. Server runs the matching onAction handler
  3. Handler mutates state via setSharedState / setPlayerState / setServerState
  4. Changed fields are automatically broadcast as deltas to connected clients
  5. The handler's return value is sent back to the calling client only

Quick Start

Step 1 — Server: Define a Room

// edgebase.config.ts
import { defineConfig } from '@edgebase/shared';

export default defineConfig({
rooms: {
'counter': {
onCreate(room) {
room.setSharedState(() => ({ count: 0 }));
},
onAction: {
INCREMENT: (payload, room, sender) => {
room.setSharedState(s => ({ ...s, count: (s.count as number) + 1 }));
return { newCount: room.getSharedState().count };
},
},
},
},
});

Step 2 — Client A: Connect & Subscribe

const room = client.room('counter', 'room-1');
await room.join();

room.onSharedState((state, changes) => {
console.log('Count:', state.count);
});

Step 3 — Client B: Connect to the Same Room

const room = client.room('counter', 'room-1');
await room.join();

room.onSharedState((state, changes) => {
document.getElementById('count')!.textContent = String(state.count);
});

Step 4 — Client A: Send an Action

const result = await room.send('INCREMENT');
console.log(result.newCount); // 1

Step 1's onAction.INCREMENT runs on the server. setSharedState triggers a delta broadcast to all connected clients — including Client B, whose onSharedState handler fires automatically.


Three State Areas

🌍

sharedState

All clients can read. Server writes only. Game board, scores, shared data.

👤

playerState

Only the owning player can read. Server writes only. HP, inventory, private hand.

🔒

serverState

Server only — never sent to clients. RNG seed, anti-cheat, internal computation.


Client API Overview

MethodDescription
room.join()Connect, authenticate, join
room.leave()Disconnect
room.send(type, payload)Send action to server, returns Promise<result>
room.getSharedState()Read current shared state
room.getPlayerState()Read current player state
room.onSharedState(handler)Subscribe to shared state changes
room.onPlayerState(handler)Subscribe to player state changes
room.onMessage(type, handler)Subscribe to server messages
room.onAnyMessage(handler)Subscribe to all server messages
room.onKicked(handler)Kicked from room
room.onError(handler)Error occurred

Server Lifecycle

HookWhenNotes
onCreate(room, ctx)First player joins (room created)Initialize shared/server state
onJoin(sender, room, ctx)Each player joinsInitialize player state. Throw to reject.
onAction[type](payload, room, sender, ctx)Client calls send()Process action, mutate state, return result
onLeave(sender, room, ctx, reason)Player leavesreason: 'leave' | 'disconnect' | 'kicked'
onDestroy(room, ctx)Last player leavesPersist final results via ctx.admin.db()

No Other BaaS Has This

Room is not a feature you'll find in Firebase, Supabase, Appwrite, or any other BaaS. Server-authoritative real-time state synchronization has traditionally required a separate multiplayer framework — and a separate server to run it on.

Colyseus / HathoraPartyKit / LiveblocksEdgeBase Room
What it isStandalone game server frameworkCollaboration SDKBuilt-in BaaS feature
Requires separate infra?Yes — dedicated Node.js serversYes — separate deploymentNo — runs inside your EdgeBase project
Auth integrationBuild your ownBuild your ownUses EdgeBase Auth (JWT, access rules)
Database accessSeparate DB neededSeparate DB neededDirect ctx.admin.db() in handlers
Delta syncManual or schema-basedCRDT-basedAutomatic diff-based deltas
3-tier stateNo (single state)NoYes — shared / player / server
CostServer hosting 24/7Per-connection pricingDO duration only — idle = $0

Room gives you a multiplayer backend that shares the same auth, database, and deployment as the rest of your app — no additional infrastructure, no separate billing, no integration glue.


Next Steps