Broadcasting
Experimental
Realtime and Broadcast are Experimental in 0.4.0. Production reliability work is still pending; review the production limits before relying on live updates.
Broadcasting pushes server-side events to the browser over WebSockets. Use it to show live activity feeds, update dashboards when data changes, or show who else is viewing a page.
You define a broadcast event on the server, send it with broadcast(...), and listen for it in your components with useFlux(...).
Quick example
This example sends a blog.post.changed event to signed-in admins whenever a post is saved.
Install broadcasting:
npx holo install broadcastDefine the event:
import { defineBroadcast, privateChannel } from '@holo-js/broadcast'
export function blogPostChanged(action: 'created' | 'updated' | 'deleted', id: number, title: string) {
return defineBroadcast({
name: 'blog.post.changed',
channels: [
privateChannel('blog.admin'),
],
payload: {
action,
id,
title,
},
})
}Decide who may listen on the private channel:
import { defineChannel } from '@holo-js/broadcast'
export default defineChannel('blog.admin', {
type: 'private',
authorize(user) {
return Boolean(user)
},
})Send the event from any server code, for example after you save a post:
import { broadcast } from '@holo-js/broadcast'
import { blogPostChanged } from '../broadcast/blog-post-changed'
export async function announcePostUpdate(post: { id: number, title: string }) {
await broadcast(blogPostChanged('updated', post.id, post.title))
}Listen for it in a component:
// app/admin/post-activity.tsx
'use client'
import { useState } from 'react'
import { useFlux } from '@holo-js/flux-react'
export function PostActivity() {
const [latest, setLatest] = useState('Waiting for post activity')
useFlux('blog.admin', 'blog.post.changed', (payload) => {
setLatest(`${payload.action}: ${payload.title}`)
})
return <p>{latest}</p>
}<!-- app/components/PostActivity.vue -->
<script setup lang="ts">
import { ref } from 'vue'
import { useFlux } from '@holo-js/flux-vue'
const latest = ref('Waiting for post activity')
useFlux('blog.admin', 'blog.post.changed', (payload) => {
latest.value = `${payload.action}: ${payload.title}`
})
</script>
<template>
<p>{{ latest }}</p>
</template><!-- src/lib/PostActivity.svelte -->
<script lang="ts">
import { useFlux } from '@holo-js/flux-svelte'
let latest = 'Waiting for post activity'
useFlux('blog.admin', 'blog.post.changed', (payload) => {
latest = `${payload.action}: ${payload.title}`
})
</script>
<p>{latest}</p>Finally, start the WebSocket worker in a second terminal next to your dev server:
npx holo broadcast:workSave a post and the component updates without a page reload.
INFO
Private channels check the signed-in user, so this example needs authentication. For a channel anyone can listen to, use channel(...) on the server and useFluxPublic(...) on the client. See Events and channels.
How it works
Three pieces take part in every broadcast:
- Your app server calls
broadcast(...). Holo sends the event to the WebSocket worker over HTTP. - The worker (
npx holo broadcast:work) keeps browser connections open and forwards the event to every socket subscribed to the channel. - The browser connects to the worker through Flux, the Holo client. Flux reads its connection settings from
/broadcasting/configand asks/broadcasting/authbefore it joins a private or presence channel.
Holo sets up both endpoints for you. You don't write route files for them.
What holo install broadcast adds
| Added | Purpose |
|---|---|
config/broadcast.ts | Connections and worker settings. See Drivers and config. |
config/redis.ts | Created if missing. Only used when you scale the worker across servers. |
server/broadcast/ | Your broadcast events. |
server/channels/ | Authorization rules for private and presence channels. |
BROADCAST_CONNECTION=holo | Added to .env, with generated BROADCAST_APP_ID, BROADCAST_APP_KEY, and BROADCAST_APP_SECRET values. .env.example gets the same names with blank values. |
@holo-js/broadcast, @holo-js/flux | Server and client packages. |
@holo-js/flux-react, @holo-js/flux-vue, or @holo-js/flux-svelte | The client helpers for your framework. |
On Next.js, Holo also writes app/broadcasting/config/route.ts, and app/broadcasting/auth/route.ts when auth is installed. Nuxt and SvelteKit serve the same URLs without extra files. If you install auth after broadcasting, holo install auth adds the auth endpoint then.
Packages
| Package | Use it for |
|---|---|
@holo-js/broadcast | Defining events and channels, sending broadcasts, running the worker. Server only. |
@holo-js/flux | The browser client. Use it directly for whispers or outside a component. |
@holo-js/flux-react | React hooks for Next.js. |
@holo-js/flux-vue | Vue composables for Nuxt. |
@holo-js/flux-svelte | Svelte helpers for SvelteKit. |
Next steps
- Events and channels: queueing broadcasts, private and presence channels, guards.
- Listening on the client: all Flux helpers, presence members, whispers, connection status.
- Drivers and config:
config/broadcast.tsand the available drivers. - Scaling in production: running the worker behind a proxy and across servers.
- Realtime queries: live query results without writing broadcast events by hand.