Understanding Server-Sent Events (SSE) with Node.js

Md. Fuad Hasan
5 min readSep 11, 2024

--

Real-time data exchange is crucial for modern web applications, from live sports updates and stock prices to chat apps and news feeds. Traditionally, we had to use methods like short polling or WebSockets for real-time communication. But there’s another simpler, more efficient option: Server-Sent Events (SSE).

SSE provides an efficient way for servers to push updates to the client over HTTP. In this guide, we’ll explain what SSE is, how it compares to other real-time technologies, and demonstrate how to use it in Node.js with a practical example.

What are Server-Sent Events (SSE)?

Server-Sent Events (SSE) allow a server to initiate a one-way stream of updates to the client over an HTTP connection. Unlike WebSockets, which allow full-duplex communication (both client and server can send messages), SSE is only one-way: the server sends updates, and the client receives them.

How does SSE work?

  • The client makes a standard HTTP request to the server.
  • The server holds this connection open and sends updates to the client as needed.
  • The client listens for these updates and processes them in real-time.

SSE is especially suited for scenarios where the server needs to send continuous or intermittent data to the client without expecting responses from the client. Examples include:

  • Live news feeds
  • Stock price updates
  • Live sports scores
  • Real-time monitoring dashboards

How Does SSE Compare to Other Technologies?

1. SSE vs WebSockets

While both technologies allow real-time communication, they have fundamental differences:

  • WebSockets offer full-duplex communication, meaning both the client and server can send messages. It’s ideal for applications that require two-way communication, such as live chats or multiplayer games.
  • SSE only allows the server to push data to the client. This makes it a simpler and lighter choice for use cases where the client does not need to send data back to the server continuously.

2. SSE vs Polling

  • Long polling involves the client making repeated HTTP requests to the server, asking if new data is available. This is inefficient because the client must keep sending requests even if there’s no new data.
  • SSE, on the other hand, establishes a single connection, and the server pushes updates whenever new data is available, eliminating the need for constant client-side polling.

Advantages of SSE

  1. Simplicity: SSE is based on HTTP, so it works easily over traditional HTTP/2 or HTTP/1.1 without the need for a more complex protocol like WebSockets.
  2. Automatic reconnection: The browser automatically reconnects to the server if the connection is dropped, making it robust and easy to maintain.
  3. Lightweight: SSE is less resource-intensive than WebSockets because it’s a simple uni-directional protocol.
  4. Cross-browser support: Modern browsers like Chrome, Firefox, and Safari have built-in support for SSE.

When to Use SSE

SSE is perfect for applications that require continuous server-to-client data streams, where:

  • The client only needs to receive updates from the server.
  • Communication can tolerate occasional delays.
  • Performance and resource efficiency are critical.

How SSE Works: The Technical Details

SSE works over a standard HTTP connection, using a specific content type and format to send updates. The server responds with a text/event-stream content type, and data is sent in the following format:

  • Data: Each message can contain multiple data fields, with each field separated by a newline (\n). The event must end with two newlines (\n\n).
  • Event: Optional custom event types can be defined.
  • ID: An optional message ID that allows the client to track and handle reconnection cases.

Here’s a simple structure of an SSE message:

id: 123
event: message
data: Hello World
data: This is another message line

SSE Example in Node.js

Let’s dive into the implementation and see how you can create a simple SSE server in Node.js and listen for updates on the client side.

Step 1: Set Up the Node.js Server

We’ll start by creating a basic Node.js server that streams events to the client. The express library can be used to handle routing, but SSE can also be implemented using native HTTP modules.

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

app.get('/events', (req, res) => {
// Set headers to keep the connection alive and tell the client we're sending event-stream data
res.setHeader('Content-Type', 'text/event-stream');
res.setHeader('Cache-Control', 'no-cache');
res.setHeader('Connection', 'keep-alive');

// Send an initial message
res.write(`data: Connected to server\n\n`);

// Simulate sending updates from the server
let counter = 0;
const intervalId = setInterval(() => {
counter++;
// Write the event stream format
res.write(`data: Message ${counter}\n\n`);
}, 2000);

// When client closes connection, stop sending events
req.on('close', () => {
clearInterval(intervalId);
res.end();
});
});

app.listen(3000, () => {
console.log('SSE server started on port 3000');
});

In this code:

  • The client requests the /events endpoint.
  • The server responds with Content-Type: text/event-stream, indicating that it will send event streams.
  • The setInterval function sends updates (messages) to the client every 2 seconds.
  • If the client disconnects, the req.on('close') event stops the server from sending further messages.

Step 2: Create the Client-Side HTML

Now, let’s create a simple HTML file to receive and display these events.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>SSE Example</title>
</head>
<body>
<h1>Server-Sent Events</h1>
<ul id="events"></ul>

<script>
// Initialize the EventSource, listening for server updates
const eventSource = new EventSource('http://localhost:3000/events');

// Listen for messages from the server
eventSource.onmessage = function(event) {
const newElement = document.createElement("li");
newElement.textContent = event.data;
document.getElementById("events").appendChild(newElement);
};

// Log connection error
eventSource.onerror = function(event) {
console.log('Error occurred:', event);
};
</script>
</body>
</html>
  • The EventSource API in the browser is used to connect to the SSE endpoint.
  • The onmessage handler listens for messages from the server and appends them to an HTML list (<ul>).
  • The browser automatically manages reconnections if the connection drops.

Step 3: Running the Application

  1. Install the necessary package:
npm install express

2. Run your server:

node app.js

3. Open the HTML file in your browser and see the server’s live updates being displayed.

Advanced Features of SSE

1. Custom Events

SSE supports custom event types. Instead of the default onmessage, you can define specific event handlers on the client side. For example:

Server-side (sending a custom event):

res.write(`event: customEvent\n`);
res.write(`data: This is a custom event message\n\n`);

Client-side (listening for the custom event):

eventSource.addEventListener('customEvent', function(event) {
console.log('Custom event received:', event.data);
});

2. Reconnection and Last-Event-ID

SSE automatically reconnects if the connection drops. The Last-Event-ID header can be used to ensure the client receives missed messages after reconnection. This is useful for ensuring data integrity during temporary connection losses.

Server-side (sending an event with an ID):

res.write(`id: 123\n`);
res.write(`data: Message with ID 123\n\n`);

Client-side (managing reconnection): The browser automatically sends the Last-Event-ID header during reconnection, and the server can use this to resume from the last message ID.

Conclusion

Server-Sent Events (SSE) offer a simple, lightweight, and efficient way to stream real-time updates from the server to the client using standard HTTP. They are ideal for applications where the client only needs to receive updates, such as live feeds, notifications, or real-time dashboards.

With automatic reconnection and cross-browser support, SSE provides a robust and developer-friendly solution for many real-time data streaming use cases. While WebSockets may be the right choice for two-way communication, SSE shines in scenarios where unidirectional communication from server to client is needed.

--

--

Responses (2)