Realtime
Channels
Channels allow you to scope events to specific people or rooms. For example:
- Chat rooms
- Emitting events to a specific user
Default Channel
By default, events are sent to the default channel. If we emit an event without specifying a channel like so:
await realtime.emit("notification.alert", "hello world!")it can automatically be read using the default channel:
useRealtime({ events: ["notification.alert"], onData({ event, data, channel }) { console.log(data) },})Custom Channels
Emit events to a specific channel:
route.ts
const channel = realtime.channel("user-123")await channel.emit("notification.alert", "hello world!")Subscribe to one or more channels:
page.tsx
"use client"import { useRealtime } from "@/lib/realtime-client"export default function Page() { useRealtime({ channels: ["user-123"], events: ["notification.alert"], onData({ event, data, channel }) { console.log(data) }, }) return <>...</>}Channel Patterns
User-Specific Channels
Send notifications to individual users:
route.ts
const channel = realtime.channel(`user-${userId}`)await channel.emit("notification.alert", "hello world!")page.tsx
useRealtime({ channels: [`user-${user.id}`], events: ["notification.alert"], onData({ data }) {},})Room-Based Channels
Broadcast to all users in a room:
route.ts
await realtime.channel(`room-${roomId}`).emit("room.message", { text: "Hello everyone!", sender: "Alice",})Team Workspaces
Scope events to team workspaces:
route.ts
await realtime.channel(`team-${teamId}`).emit("project.update", { project: "Website Redesign", status: "In Progress",})Dynamic Channels
Subscribe to multiple channels at the same time:
page.tsx
"use client"import { useState } from "react"import { useRealtime } from "@/lib/realtime-client"export default function Page() { const [channels, setChannels] = useState<string[]>(["lobby"]) useRealtime({ channels, events: ["chat.message"], onData({ event, data, channel }) { console.log(`Message from ${channel}:`, data) }, }) const joinRoom = (roomId: string) => { setChannels((prev) => [...prev, roomId]) } const leaveRoom = (roomId: string) => { setChannels((prev) => prev.filter((c) => c !== roomId)) } return ( <div> <p>Active channels: {channels.join(", ")}</p> <button onClick={() => joinRoom("room-1")}>Join Room 1</button> <button onClick={() => joinRoom("room-2")}>Join Room 2</button> <button onClick={() => leaveRoom("lobby")}>Leave Lobby</button> </div> )}Broadcasting to Multiple Channels
Emit to multiple channels at the same time:
route.ts
const rooms = ["lobby", "room-1", "room-2"]await Promise.all( rooms.map((room) => { const channel = realtime.channel(room) return channel.emit("chat.message", `Hi channel ${room}!`) }))Channel Security
Combine channels with middleware for secure access control:
app/api/realtime/route.ts
import { handle } from "@upstash/realtime"import { realtime } from "@/lib/realtime"import { currentUser } from "@/auth"export const GET = handle({ realtime, middleware: async ({ request, channels }) => { const user = await currentUser(request) for (const channel of channels) { if (!user.canAccessChannel(channel)) { return new Response("Unauthorized", { status: 401 }) } } },})Authenticate Realtime Requests
See the middleware documentation for authentication examples