Files
wehub-resource-sync 3a28426bf4
Lint and Format Check / lint-and-format (push) Failing after 0s
Check Migrations / Check for duplicate migration numbers (push) Failing after 1s
CI Pre-merge Check / CI Pre-merge Check (push) Failing after 2m17s
chore: import upstream snapshot with attribution
2026-07-13 12:23:40 +08:00

189 lines
6.8 KiB
Plaintext

---
title: "Realtime"
sidebarTitle: "Overview"
description: "Send database changes, broadcasts, presence, and webhook fan-out through realtime channels."
---
Use InsForge Realtime when your app needs to update without a page refresh. Clients subscribe to channels such as `order:123` or `chat:room-1`, then receive database changes, broadcasts, and presence updates over WebSockets. Channels can also fan out the same messages to webhook URLs when another service should receive the event.
<Frame caption="Realtime dashboard: channel patterns, message history, permissions, and retention settings.">
<img src="/images/dashboard-realtime.png" alt="InsForge Realtime dashboard" />
</Frame>
<Note>
**Need server-side code to run after a database change?** Put that business logic in an [Edge Function](/core-concepts/functions/overview) and invoke it from a database trigger. Use Realtime when the change should be delivered to connected clients or configured webhook endpoints.
</Note>
```mermaid
graph TB
App[Client application] --> SDK[InsForge SDK]
SDK --> Channel[Realtime channel]
Database[(Postgres)] --> Trigger[Database trigger]
Trigger --> Channel
Channel --> WebSocket[WebSocket subscribers]
Channel --> Presence[Presence state]
Channel --> Webhook[Webhook URLs]
Channel --> History[(Message history)]
Auth[Auth token and RLS] --> Channel
style App fill:#1e293b,stroke:#475569,color:#e2e8f0
style SDK fill:#1e40af,stroke:#3b82f6,color:#dbeafe
style Channel fill:#166534,stroke:#22c55e,color:#dcfce7
style Database fill:#0e7490,stroke:#06b6d4,color:#cffafe
style Trigger fill:#4c1d95,stroke:#8b5cf6,color:#ede9fe
style WebSocket fill:#c2410c,stroke:#fb923c,color:#fed7aa
style Presence fill:#c2410c,stroke:#fb923c,color:#fed7aa
style Webhook fill:#c2410c,stroke:#fb923c,color:#fed7aa
style History fill:#0e7490,stroke:#06b6d4,color:#cffafe
style Auth fill:#4c1d95,stroke:#8b5cf6,color:#ede9fe
```
## Features
### Channels
Channels are named topics that clients can join. Use exact names for shared rooms, or patterns like `order:%` when every record needs its own live stream.
### Database changes
Use database changes when a table write should become a live app event. Create a trigger on the table you want to watch. In its trigger function, call the predefined `realtime.publish(channel, event, payload)` function to decide which channel receives the message, which event name clients handle, and what payload they receive.
For a channel pattern such as `order:%`, a trigger can publish one event per order:
```sql
CREATE OR REPLACE FUNCTION public.notify_order_status()
RETURNS TRIGGER AS $$
BEGIN
PERFORM realtime.publish(
'order:' || NEW.id::text,
'status_changed',
jsonb_build_object(
'id', NEW.id,
'status', NEW.status,
'updatedAt', NEW.updated_at
)
);
RETURN NEW;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;
CREATE TRIGGER order_status_realtime
AFTER UPDATE OF status ON public.orders
FOR EACH ROW
WHEN (OLD.status IS DISTINCT FROM NEW.status)
EXECUTE FUNCTION public.notify_order_status();
```
Then subscribe from the app with the SDK:
```typescript
const channel = `order:${orderId}`;
await insforge.realtime.connect();
const subscription = await insforge.realtime.subscribe(channel);
if (!subscription.ok) {
throw new Error(subscription.error.message);
}
insforge.realtime.on('status_changed', (message) => {
renderOrderStatus(message.status);
});
```
### Client broadcasts
Clients can publish messages to channels they have already joined. Use this for chat, typing indicators, cursors, collaborative editing signals, and other user-to-user updates that do not need to start from a database write.
```typescript
await insforge.realtime.publish(`chat:${roomId}`, 'typing', {
userId,
isTyping: true
});
```
### Webhooks
Attach webhook URLs to a channel when another service should receive each message. InsForge posts the event payload to every configured URL, includes headers for the event name, channel, and message ID, retries transient network failures, and records webhook delivery counts in message history.
### Presence
Presence tracks who is online in a channel. Clients receive the current member snapshot when they subscribe, then `presence:join` and `presence:leave` events as members come and go. Store durable room membership, roles, and permissions in your own tables; presence is only online state.
```typescript
const response = await insforge.realtime.subscribe(`chat:${roomId}`);
if (response.ok) {
renderOnlineMembers(response.presence.members);
}
insforge.realtime.on('presence:join', (message) => {
addOnlineMember(message.member);
});
insforge.realtime.on('presence:leave', (message) => {
removeOnlineMember(message.member.presenceId);
});
```
### Row-level security
Realtime can be open while prototyping, then locked down with Postgres RLS. Use `SELECT` policies on `realtime.channels` to control who can subscribe, and `INSERT` policies on `realtime.messages` to control who can publish from a client.
This policy lets authenticated users subscribe to `order:<id>` channels only when the order belongs to them:
```sql
ALTER TABLE realtime.channels ENABLE ROW LEVEL SECURITY;
CREATE POLICY "users_subscribe_own_orders"
ON realtime.channels
FOR SELECT
TO authenticated
USING (
pattern = 'order:%'
AND EXISTS (
SELECT 1
FROM public.orders
WHERE id = NULLIF(split_part(realtime.channel_name(), ':', 2), '')::uuid
AND user_id = auth.uid()
)
);
```
Use `realtime.channel_name()` in subscribe policies because clients subscribe to resolved channels such as `order:123`, while `realtime.channels` stores patterns such as `order:%`.
### Message history
Every delivered event is recorded with WebSocket and webhook delivery counts. The dashboard can inspect recent messages, delivery stats, and retention settings when you need to debug live behavior.
## Build with it
<CardGroup cols={2}>
<Card title="TypeScript SDK" icon="js" href="/sdks/typescript/realtime">
Subscribe to channels, publish events, and track presence from Node, browser, and edge.
</Card>
<Card title="Swift SDK" icon="swift" href="/sdks/swift/realtime">
Native Swift realtime client for iOS and macOS.
</Card>
<Card title="Kotlin SDK" icon="android" href="/sdks/kotlin/realtime">
Coroutines-first realtime client for Android and JVM.
</Card>
<Card title="REST and WebSocket API" icon="code" href="/sdks/rest/realtime">
Use the raw Socket.IO contract from any language.
</Card>
</CardGroup>
## Next steps
- Set up the [CLI](/quickstart) to link your project.
- Create channels in the Realtime dashboard.
- Use the [TypeScript SDK reference](/sdks/typescript/realtime) for client subscriptions.
- Add webhook URLs to a channel when another service needs the same event stream.