DEV Community

Cover image for WebSockets are Overkill: Build Real-Time Dashboards with Server-Sent Events (SSE) 🚀
Marce
Marce

Posted on

WebSockets are Overkill: Build Real-Time Dashboards with Server-Sent Events (SSE) 🚀

When developers hear "real-time," their first instinct is usually to reach for WebSockets. But what if I told you that for many use cases, WebSockets are actually overkill?

If you are building a chat application or a multiplayer game where the client and server constantly talk to each other, WebSockets are perfect. However, if you are building a live metrics dashboard, a stock ticker, or a news feed, the communication is strictly one-way: the server pushes updates to the client.

For these unidirectional streams, Server-Sent Events (SSE) are a much better architectural choice.

In this tutorial, I'll show you how I built a lightweight, real-time server dashboard using Node.js and native SSE—no heavy libraries required.

🧠 Why SSE over WebSockets?

Native HTTP: SSE operates over standard HTTP/HTTPS. You don't need custom protocols, complex proxy configurations, or firewall bypasses.

Auto-Reconnect: The browser's native API handles connection drops and retries automatically out of the box.

Resource Efficiency: It uses a single, long-lived HTTP connection, making it much lighter on server resources for one-way data broadcasting.

🛠️ Step 1: The Node.js Backend

We need a simple Express server that configures the specific headers required for an SSE stream (text/event-stream).

const express = require('express');
const cors = require('cors');
const app = express();


app.use(cors());

app.get('/events', (req, res) => {
    // 1. Mandatory SSE Headers
    res.setHeader('Content-Type', 'text/event-stream');
    res.setHeader('Cache-Control', 'no-cache');
    res.setHeader('Connection', 'keep-alive');

    // 2. Push data to the client every 3 seconds
    const intervalId = setInterval(() => {
        const data = JSON.stringify({
            message: "System update notification",
            activeUsers: Math.floor(Math.random() * (500 - 100 + 1) + 100),
            cpuLoad: (Math.random() * 100).toFixed(1) + "%",
            timestamp: new Date().toISOString()
        });

        // Note: The SSE format strictly requires "data: " and TWO newlines
        res.write(`data: ${data}\n\n`);
    }, 3000);

    // 3. Clean up when the client disconnects
    req.on('close', () => {
        clearInterval(intervalId);
    });
});

app.listen(3000, () => console.log('SSE Server running!'));

Enter fullscreen mode Exit fullscreen mode

💻 Step 2: The Vanilla JS Frontend

The best part about SSE is that you don't need any external libraries on the frontend. Modern browsers have the EventSource API built-in.

// Connect to the backend stream
const eventSource = new EventSource('http://localhost:3000/events');

// Listen for incoming messages
eventSource.onmessage = function(event) {
    // Parse the JSON payload from the server
    const data = JSON.parse(event.data);

    console.log(`Update at ${data.timestamp}: CPU is at ${data.cpuLoad}`);

    // Here you would dynamically update your DOM elements
};

// Handle connection errors (the browser will auto-reconnect!)
eventSource.onerror = function(error) {
    console.error('SSE Error:', error);
};

Enter fullscreen mode Exit fullscreen mode

🏁 Conclusion

While WebSockets often steal the spotlight, Server-Sent Events remain one of the most elegant, efficient, and underutilized tools in a backend developer's arsenal for real-time, one-way data streaming.

You can check out the full source code and the complete UI dashboard in My GitHub Repository Here.

Have you used SSE in production? Let me know in the comments!

I'm Marcela Zapata Vanegas, Technical Writer & Full Stack Developer. I specialize in building and documenting cloud-native solutions.

Top comments (0)