Realtime
You want your UI to update the moment something changes on the server. A new message appears in the chat. A task gets completed and the board updates. A live cursor shows where another user is typing.
Slingshot has two built-in transports for this. Pick the one that matches your use case.
Choose your transport
Section titled “Choose your transport”| You want to… | Use |
|---|---|
| Show live updates when data changes (dashboard, feed, notifications) | SSE |
| Build chat, collaborative editing, or live cursors | WebSockets |
| Stream event-bus events to browser clients | SSE |
| Manage rooms, presence, or connection state | WebSockets |
| Keep infrastructure simple | SSE |
SSE: live updates from the event bus
Section titled “SSE: live updates from the event bus”SSE streams server events to browser clients over a simple HTTP connection. It plugs directly into the event bus — publish an event, mark it as client-safe, and browsers receive it automatically.
// @skip-typecheckimport { defineEvent } from '@lastshotlabs/slingshot';
// Mark events as client-safe so they reach browsersevents.register( defineEvent('task.completed', { ownerPlugin: 'app', exposure: ['client-safe'], resolveScope(payload) { return { userId: payload.userId }; }, }),);Browser side:
const es = new EventSource('/events', { withCredentials: true });es.onmessage = event => { const data = JSON.parse(event.data); console.log('Live update:', data);};That is it. No WebSocket server, no rooms, no connection management. The event bus does the heavy lifting.
See Server-Sent Events for the full setup including auth, scoping, and filtering.
WebSockets: bidirectional communication
Section titled “WebSockets: bidirectional communication”WebSockets are for features where clients send messages back. Chat, collaborative editing, live cursors, multiplayer — anything that needs low-latency two-way communication.
// @skip-typecheckimport { defineApp } from '@lastshotlabs/slingshot';
declare function verifyToken(token: string): string | null;
export default defineApp({ port: 3000, ws: { endpoints: { '/ws/chat': { upgrade: async req => { const auth = req.headers.get('authorization'); const token = auth?.startsWith('Bearer ') ? auth.slice('Bearer '.length) : null; if (!token) return new Response('Unauthorized', { status: 401 }); const userId = verifyToken(token); if (!userId) return new Response('Unauthorized', { status: 401 }); return { actorId: userId }; }, on: { open: ws => { ws.subscribe('general'); }, message: (ws, message) => { ws.publish('general', message); }, close: ws => { ws.unsubscribe('general'); }, }, }, }, },});Browser side:
const ws = new WebSocket('ws://localhost:3000/ws/chat');ws.onmessage = event => console.log('Message:', event.data);ws.send(JSON.stringify({ text: 'Hello everyone' }));Bun’s built-in pub/sub handles rooms. Clients subscribe to named rooms and publish to them without any external dependencies.
See WebSockets for rooms, presence, auth guards, entity channels, and scaling.
How they relate to events
Section titled “How they relate to events”SSE is tightly coupled to the event model. You publish events and SSE exposes selected ones to browsers.
WebSockets are a separate transport. They have their own connection lifecycle, rooms, and message handling. They can participate in the event model, but they are not just “events over another wire.”
Scaling
Section titled “Scaling”- SSE scales with your event bus. Switch to BullMQ or Redis and SSE events cross instance boundaries automatically.
- WebSockets need explicit planning. Bun’s pub/sub is in-process — for multi-instance deployments, add a Redis transport.
Read Horizontal Scaling when you move beyond a single instance.
Next in your journey
Section titled “Next in your journey”Realtime is online. Most apps also have work that should run outside the request cycle — emails, exports, retries, scheduled cleanup:
- Jobs and Orchestration — durable background work, retries, and multi-step workflows.
Go deeper into realtime
Section titled “Go deeper into realtime”- Server-Sent Events — full SSE authoring guide
- WebSockets — rooms, presence, entity channels, scaling
- WebSockets Guide — advanced entity-channel and scaling patterns
- Realtime with SSE Example — complete working example
- Horizontal Scaling — multi-instance transport setup