Sse Nodejs
title: "Advanced SSE in Node.js" description: "Learn advanced Server-Sent Event patterns in Node.js including connection pooling, event multiplexing, backpressure handling, and cluster support." weight: 17 date: 2026-06-28 lastmod: 2026-06-28 tags: ["apis", "sse"]
Node.js is well-suited for SSE due to its event-driven, non-blocking architecture. This lesson covers advanced patterns for building production-grade SSE servers.
## What You'll Learn
- Connection pooling and management
- Event filtering and multiplexing
- Backpressure handling
- Clustering for horizontal scaling
- Redis pub/sub for cross-instance events
## Why It Matters
Production SSE servers must handle thousands of connections, manage memory efficiently, and scale horizontally. Advanced patterns ensure your SSE infrastructure is reliable and performant.
## Real-World Use
A real-time analytics platform uses clustered Node.js SSE servers behind a load balancer. Redis pub/sub synchronizes events across instances, and each connection is tracked with metadata for targeted event delivery.
## Flow Chart
```mermaid
flowchart LR
A[Load Balancer] --> B[Node Cluster 1]
A --> C[Node Cluster 2]
A --> D[Node Cluster 3]
B --> E[Redis Pub/Sub]
C --> E
D --> E
E --> F[Event Sources]
F --> G[Application Events]
Code Examples
Example 1: Connection Pool with Backpressure
const http = require('http');
class SSEPool {
constructor() {
this.clients = new Map();
this.writeQueue = new Map();
this.maxQueued = 100;
}
addClient(req, res) {
const id = `${req.socket.remoteAddress}-${Date.now()}-${Math.random()}`;
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive',
});
this.clients.set(id, res);
this.writeQueue.set(id, []);
res.on('close', () => {
this.clients.delete(id);
this.writeQueue.delete(id);
});
return id;
}
sendToClient(id, data) {
const res = this.clients.get(id);
if (!res) return false;
const queue = this.writeQueue.get(id);
// Check for backpressure
if (queue.length >= this.maxQueued) {
console.warn(`Client ${id} backpressure detected, closing`);
res.end();
this.clients.delete(id);
this.writeQueue.delete(id);
return false;
}
const message = `data: ${JSON.stringify(data)}\n\n`;
const canWrite = res.write(message);
if (!canWrite) {
// Backpressure: queue the message
queue.push(data);
res.once('drain', () => this.flushQueue(id));
}
return true;
}
flushQueue(id) {
const queue = this.writeQueue.get(id);
const res = this.clients.get(id);
if (!queue || !res) return;
while (queue.length > 0) {
const data = queue.shift();
const message = `data: ${JSON.stringify(data)}\n\n`;
if (!res.write(message)) {
// Still backpressure, wait for next drain
res.once('drain', () => this.flushQueue(id));
break;
}
}
}
broadcast(data) {
this.clients.forEach((res, id) => {
this.sendToClient(id, data);
});
}
getStats() {
return {
totalClients: this.clients.size,
queuedMessages: Array.from(this.writeQueue.values())
.reduce((sum, q) => sum + q.length, 0),
};
}
}
const pool = new SSEPool();
const server = http.createServer((req, res) => {
if (req.url === '/events') {
pool.addClient(req, res);
} else if (req.url === '/stats') {
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify(pool.getStats()));
} else {
res.writeHead(404);
res.end();
}
});
server.listen(3000);
Expected output: SSE connection pool with backpressure handling, queue management, and monitoring stats.
Example 2: Event Multiplexing
const http = require('http');
const { EventEmitter } = require('events');
class SSEMultiplexer extends EventEmitter {
constructor() {
super();
this.connections = new Map();
}
createConnection(req, res) {
const channels = new Set(req.url.split('?channels=')[1]?.split(',') || ['*']);
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
});
const id = `${Date.now()}-${Math.random()}`;
this.connections.set(id, { res, channels });
// Send available channels
res.write(`event: channels\ndata: ${JSON.stringify(Array.from(channels))}\n\n`);
res.on('close', () => this.connections.delete(id));
return id;
}
publish(channel, event, data) {
const message = event
? `event: ${event}\ndata: ${JSON.stringify(data)}\n\n`
: `data: ${JSON.stringify(data)}\n\n`;
this.connections.forEach((conn) => {
if (conn.channels.has('*') || conn.channels.has(channel)) {
conn.res.write(message);
}
});
}
}
const multiplexer = new SSEMultiplexer();
// Server
http.createServer((req, res) => {
if (req.url.startsWith('/events')) {
multiplexer.createConnection(req, res);
} else {
res.writeHead(404);
res.end();
}
}).listen(3000);
// Event sources
const events = [
{ channel: 'stocks', event: 'price', data: { symbol: 'AAPL', price: 175 } },
{ channel: 'news', event: 'headline', data: { title: 'Market Update' } },
{ channel: 'weather', event: 'alert', data: { type: 'storm' } },
{ channel: 'stocks', event: 'price', data: { symbol: 'GOOG', price: 140 } },
];
let index = 0;
setInterval(() => {
const evt = events[index % events.length];
multiplexer.publish(evt.channel, evt.event, evt.data);
index++;
}, 2000);
Expected output: SSE multiplexer allows clients to subscribe to specific channels and receive only matching events.
Example 3: Clustered SSE with Redis
const http = require('http');
const { Worker } = require('cluster');
const Redis = require('ioredis');
if (require('cluster').isMaster) {
const numCPUs = require('os').cpus().length;
for (let i = 0; i < numCPUs; i++) {
require('cluster').fork();
}
require('cluster').on('exit', (worker) => {
console.log(`Worker ${worker.process.pid} died, restarting`);
require('cluster').fork();
});
} else {
const redis = new Redis();
const sub = new Redis();
const clients = new Map();
http.createServer((req, res) => {
if (req.url === '/events') {
const id = `${process.pid}-${Date.now()}`;
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
});
clients.set(id, res);
res.on('close', () => clients.delete(id));
}
}).listen(3000);
// Listen for cross-instance events
sub.subscribe('sse-events');
sub.on('message', (channel, message) => {
const data = JSON.parse(message);
clients.forEach((res) => {
res.write(`data: ${JSON.stringify(data)}\n\n`);
});
});
// Publish local events to all instances
function publishToAll(data) {
redis.publish('sse-events', JSON.stringify(data));
}
// Simulate events
setInterval(() => {
publishToAll({
message: `Event from worker ${process.pid}`,
time: Date.now(),
});
}, 5000);
console.log(`Worker ${process.pid} started`);
}
Expected output: Clustered SSE with Redis pub/sub synchronizing events across all worker processes.
Common Mistakes
| Mistake | Explanation |
|---|---|
| Not handling backpressure | Without backpressure handling, slow clients cause memory growth from buffered writes |
| Using process.memoryUsage without monitoring | SSE connections consume memory; monitor and set connection limits |
| Broadcasting to all without filtering | Always filter events per client to avoid overwhelming clients and wasting bandwidth |
| Not using cluster mode for multiple cores | Node.js single-thread limits parallelism; use cluster or worker_threads for scale |
| Forgetting Redis error handling | Redis connection failures break cross-instance communication; implement fallbacks |
Practice Questions
- How do you detect and handle backpressure in Node.js SSE?
- How do you implement event channel multiplexing?
- How does clustering improve SSE server performance?
- How do you use Redis to synchronize events across SSE server instances?
- What metrics should you monitor for SSE connections?
Challenge
Build a production-grade SSE server with clustering, Redis pub/sub for cross-instance events, per-client event filtering, backpressure handling, and Prometheus metrics for monitoring connection counts and throughput.
FAQ
Mini Project
Build a horizontally scalable SSE infrastructure for a live notification system. Use Node.js cluster mode, Redis pub/sub for cross-instance communication, per-user event filtering, backpressure handling, and health monitoring endpoints.
What's Next
Learn about SSE named event types
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro