Realtime Architecture and Concepts
What is Realtime?
In traditional web applications, clients request data and servers respond. To get updates, clients must request again. Realtime changes this paradigmβservers push updates to clients as they happen.
The Traditional Request-Response Model
βββββββββββ βββββββββββ
β Client β 1. Request: GET /posts β Server β
β β ββββββββββββββββββββββββββββββ β
β β β β
β β 2. Response: [posts...] β β
β β ββββββββββββββββββββββββββββ β β
β β β β
β Time β 3. Wait... β β
β passes β β β
β β 4. Request: GET /posts β β
β β ββββββββββββββββββββββββββββββ β
β β β β
β β 5. Response: [posts...] β β
β β ββββββββββββββββββββββββββββ β β
βββββββββββ βββββββββββ
Problem: Client doesn't know when new data exists
Solution: Poll repeatedly (inefficient)
The Realtime Model
βββββββββββ βββββββββββ
β Client β 1. Subscribe to changes β Server β
β β ββββββββββββββββββββββββββββββ β
β β (WebSocket connection) β β
β β β β
β β β β Data β
β β 2. Push: New post created β changesβ
β β ββββββββββββββββββββββββββββββ β
β β β β
β β β β Data β
β β 3. Push: Post updated β changesβ
β β ββββββββββββββββββββββββββββββ β
β β β β
β β 4. Unsubscribe β β
β β ββββββββββββββββββββββββββββββ β
βββββββββββ βββββββββββ
Benefit: Instant updates, no polling
Supabase Realtime Architecture
Supabase Realtime is built on several technologies:
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Client Applications β
β (Web, Mobile, Desktop) β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
WebSocket Connection
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Supabase Realtime Server β
β (Phoenix/Elixir) β
β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Channels β β
β β ββββββββββββ ββββββββββββ ββββββββββββββββββββ β β
β β β Postgres β βBroadcast β β Presence β β β
β β β Changes β β β β β β β
β β ββββββββββββ ββββββββββββ ββββββββββββββββββββ β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
β PostgreSQL Replication
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β PostgreSQL β
β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Write-Ahead Log (WAL) β β
β β (Records all database changes) β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Three Types of Realtime Features
1. Postgres Changes
Listen to database INSERT, UPDATE, DELETE events:
// Subscribe to new posts
supabase
.channel('posts')
.on('postgres_changes', {
event: 'INSERT',
schema: 'public',
table: 'posts'
}, (payload) => {
console.log('New post:', payload.new)
})
.subscribe()
2. Broadcast
Send arbitrary messages to connected clients:
// Send a message to all clients in the room
const channel = supabase.channel('room:123')
channel.send({
type: 'broadcast',
event: 'cursor_move',
payload: { x: 100, y: 200, userId: 'abc' }
})
3. Presence
Track who's online and their state:
// Track user presence
const channel = supabase.channel('room:123')
channel.on('presence', { event: 'sync' }, () => {
const state = channel.presenceState()
console.log('Online users:', Object.keys(state))
})
channel.subscribe(async (status) => {
if (status === 'SUBSCRIBED') {
await channel.track({
user_id: currentUser.id,
online_at: new Date().toISOString()
})
}
})
How Postgres Changes Works
Supabase uses PostgreSQL's logical replication feature to detect changes:
Write-Ahead Log (WAL)
PostgreSQL records all changes to a log before applying them:
WAL Entry Example:
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Transaction: 12345 β
β Table: public.posts β
β Operation: INSERT β
β New Row: {id: 'uuid', title: 'Hello', content: '...'} β
β Timestamp: 2024-01-15 10:30:00 β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Replication Slots
Supabase creates a replication slot that reads the WAL:
ββββββββββββββββββ ββββββββββββββββββ βββββββββββββββββββ
β PostgreSQL βββββββ Replication βββββββ Realtime β
β (WAL) β β Slot β β Server β
ββββββββββββββββββ ββββββββββββββββββ βββββββββββββββββββ
Change Filtering
The Realtime server filters changes based on subscriptions:
// Client subscribes to specific table and filter
.on('postgres_changes', {
event: 'INSERT',
schema: 'public',
table: 'messages',
filter: 'room_id=eq.123' // Only messages in room 123
}, handleNewMessage)
The server only sends changes matching the subscription.
WebSocket Connections
What is a WebSocket?
A WebSocket is a persistent, bidirectional connection:
HTTP (Traditional):
Client βββ Request βββ Server
Client βββ Response βββ Server
(Connection closes)
WebSocket (Realtime):
Client βββββββββββββββββ Server
(Connection stays open)
(Either side can send anytime)
Connection Lifecycle
1. Client initiates WebSocket handshake
GET /realtime/v1/websocket HTTP/1.1
Upgrade: websocket
2. Server accepts
HTTP/1.1 101 Switching Protocols
3. Connection established
Client ββββββββββββββββββ Server
4. Messages flow both directions
5. Either side can close
Connection Management
The Supabase SDK handles connection management:
const channel = supabase.channel('my-channel')
// Subscribe (opens connection if needed)
channel.subscribe((status) => {
console.log('Status:', status)
// SUBSCRIBED, CHANNEL_ERROR, TIMED_OUT, CLOSED
})
// Unsubscribe (closes when no more subscriptions)
channel.unsubscribe()
Channels
A channel is a named communication pipe:
// Different channels for different purposes
const postsChannel = supabase.channel('posts')
const chatChannel = supabase.channel('chat:room-123')
const presenceChannel = supabase.channel('presence:lobby')
Channel Naming Conventions
posts // Simple name
chat:room-123 // Hierarchical (chat feature, specific room)
user:uuid:updates // User-specific channel
Multiple Subscriptions Per Channel
One channel can have multiple event handlers:
const channel = supabase.channel('app-events')
channel
.on('postgres_changes', {
event: '*',
schema: 'public',
table: 'posts'
}, handlePostChange)
.on('postgres_changes', {
event: '*',
schema: 'public',
table: 'comments'
}, handleCommentChange)
.on('broadcast', {
event: 'notification'
}, handleNotification)
.subscribe()
RLS and Realtime
Important: Row Level Security applies to Realtime subscriptions!
-- RLS policy
CREATE POLICY "Users see own posts"
ON posts FOR SELECT
USING (user_id = auth.uid());
-- Realtime subscription
// User A subscribes to posts
supabase.channel('posts').on('postgres_changes', {
event: '*',
schema: 'public',
table: 'posts'
}, handler).subscribe()
// When User B creates a post:
// - User A only receives the event if the RLS policy allows
// - User A's auth.uid() is checked against the new row
What This Means
- You can't receive events for data you can't query
- Subscriptions are automatically filtered by RLS
- Security is consistent across API and Realtime
Use Cases
Live Dashboards
// Subscribe to metrics changes
supabase
.channel('metrics')
.on('postgres_changes', {
event: '*',
schema: 'public',
table: 'metrics'
}, updateDashboard)
.subscribe()
Chat Applications
// Subscribe to messages in a room
supabase
.channel(`room:${roomId}`)
.on('postgres_changes', {
event: 'INSERT',
schema: 'public',
table: 'messages',
filter: `room_id=eq.${roomId}`
}, displayMessage)
.subscribe()
Collaborative Editing
// Broadcast cursor positions
channel.send({
type: 'broadcast',
event: 'cursor',
payload: { userId, position }
})
// Track presence
channel.track({ userId, name, status: 'editing' })
Notifications
// Subscribe to user-specific notifications
supabase
.channel(`user:${userId}`)
.on('postgres_changes', {
event: 'INSERT',
schema: 'public',
table: 'notifications',
filter: `user_id=eq.${userId}`
}, showNotification)
.subscribe()
Key Takeaways
- Realtime enables push: Server sends data as it changes
- Three features: Postgres Changes, Broadcast, Presence
- Built on PostgreSQL WAL: Reliable change detection
- WebSocket connections: Persistent, bidirectional
- Channels organize subscriptions: Named communication pipes
- RLS applies: Security consistent with queries
Looking Ahead
Now that you understand the architecture, we'll dive deeper into Postgres Changes and how Change Data Capture works.
Realtime transforms user experiences. Instead of stale data and manual refresh buttons, your applications can show the world as it changes, instantly.
Discussion
Sign in to join the discussion.

