Skip to content

SSE Transport

The SSE (Server-Sent Events) transport enables efficient server-to-client streaming over HTTP.

Terminal window
bun add @pubsubjs/transport-sse

Server-Sent Events is a standard for pushing updates from server to client over HTTP:

  • Unidirectional: Server → Client only
  • Auto-reconnect: Built-in reconnection handling
  • Simple: Works over standard HTTP
  • Firewall-friendly: Uses regular HTTP port

PubSubJS provides a client transport only. You can use it with any SSE server that emits events in one of these formats:

{ "channel": "notification", "payload": { "message": "hi" } }

or as SSE event types, where the event name is the channel and the data is either the payload or { "payload": ..., "attributes": ... }.

import { SSEClientTransport } from "@pubsubjs/transport-sse";
import { Subscriber } from "@pubsubjs/core";
import { events } from "./events";
const transport = new SSEClientTransport({
url: "http://localhost:3000/events",
});
const subscriber = new Subscriber({ events, transport });
subscriber.on("notification", (payload) => {
showNotification(payload.message);
});
await subscriber.subscribe();
const transport = new SSEClientTransport({
// SSE endpoint URL
url: "https://api.example.com/events",
// Include cookies with the request
withCredentials: true,
// Reconnection
autoReconnect: true,
// Custom headers via query params (SSE doesn't support custom headers)
queryParams: {
token,
},
});
import { useEffect, useState } from "react";
import { SSEClientTransport } from "@pubsubjs/transport-sse";
import { Subscriber } from "@pubsubjs/core";
function useSSENotifications() {
const [notifications, setNotifications] = useState([]);
useEffect(() => {
const transport = new SSEClientTransport({
url: "/api/events",
});
const subscriber = new Subscriber({ events, transport });
subscriber.on("notification", (payload) => {
setNotifications((prev) => [...prev, payload]);
});
subscriber.subscribe();
return () => subscriber.unsubscribe();
}, []);
return notifications;
}
const transport = new SSEClientTransport({
url: "https://api.example.com/events",
});
const subscriber = new Subscriber({ events, transport });
subscriber.on("notification", (payload) => {
toast.show(payload.message);
});
await subscriber.subscribe();
const transport = new SSEClientTransport({
url: "https://api.example.com/events",
});
const subscriber = new Subscriber({ events, transport });
subscriber.on("metrics.update", (payload) => {
updateChart(payload.cpu, payload.memory);
updateTable(payload.requests);
});
await subscriber.subscribe();
const transport = new SSEClientTransport({
url: "https://api.example.com/events",
});
const subscriber = new Subscriber({ events, transport });
subscriber.on("feed.update", (payload) => {
if (payload.type === "new_post") {
prependToFeed(payload.post);
}
});
await subscriber.subscribe();
// Client
const transport = new SSEClientTransport({
url: `https://api.example.com/events?token=${token}`,
});
// Client (cookies sent automatically)
const transport = new SSEClientTransport({
url: "https://api.example.com/events",
withCredentials: true,
});
FeatureSSEWebSocket
DirectionServer → ClientBidirectional
ProtocolHTTPWebSocket
ReconnectionBuilt-inManual
Binary dataNo (text only)Yes
Browser supportAll modernAll modern
Proxy/firewallUsually worksMay be blocked

Use SSE when:

  • You only need server-to-client communication
  • Firewalls block WebSocket
  • You want simpler infrastructure

Use WebSocket when:

  • You need bidirectional communication
  • You’re sending binary data
  • You need lower latency

Browsers limit SSE connections per domain (usually 6). Use a single connection with channel multiplexing:

// Client subscribes to one endpoint, receives multiple event types
subscriber.on("notification", handleNotification);
subscriber.on("metrics", handleMetrics);
subscriber.on("feed", handleFeed);
// Fall back to polling if SSE not supported
if (typeof EventSource === "undefined") {
startPolling();
} else {
startSSE();
}