Backend

Using Server-Sent Events with JSON in Node.js

October 27, 20258 min readBy JSON Formatter Team

Learn how to implement real-time data streaming from server to client using Server-Sent Events and JSON in Node.js applications. Discover the power of one-way server push technology.

Real-Time Communication: Server-Sent Events (SSE) enable servers to push real-time updates to clients over a single, long-lived HTTP connection. Combined with JSON, SSE provides an efficient way to stream structured data to web applications.

What Are Server-Sent Events?

Server-Sent Events (SSE) is a web standard that allows a server to push data to a client over a persistent HTTP connection. Unlike traditional HTTP requests where the client repeatedly polls the server, SSE enables unidirectional communication from server to client.

SSE is particularly useful for applications requiring real-time updates such as live news feeds, stock prices, social media updates, and progress indicators. The connection remains open, allowing the server to send data whenever new information becomes available.

Why Use SSE with JSON?

JSON is the ideal data format for SSE because:

Structured Data

JSON provides a structured format for sending complex data objects through SSE streams

Universal Support

JSON is natively supported in JavaScript, making client-side parsing seamless

Lightweight

JSON is human-readable and compact, reducing bandwidth requirements

Easy Parsing

JavaScript's JSON.parse() makes it trivial to extract data from SSE messages

Setting Up SSE in Node.js

To implement Server-Sent Events in Node.js, you'll need to create an HTTP server that handles SSE connections and sends events in the proper format.

Creating an SSE Server

Here's how to set up a basic SSE server in Node.js:

const http = require('http');

const server = http.createServer((req, res) => {
  if (req.url === '/sse-endpoint') {
    // Set SSE headers
    res.writeHead(200, {
      'Content-Type': 'text/event-stream',
      'Cache-Control': 'no-cache',
      'Connection': 'keep-alive',
      'Access-Control-Allow-Origin': '*'
    });

    // Send initial connection confirmation
    res.write('data: ' + JSON.stringify({ 
      status: 'connected', 
      message: 'SSE connection established' 
    }) + '\n\n');

    // Send periodic updates
    const interval = setInterval(() => {
      const data = {
        timestamp: new Date().toISOString(),
        message: 'Server update',
        value: Math.random()
      };
      res.write('data: ' + JSON.stringify(data) + '\n\n');
    }, 1000);

    // Clean up on client disconnect
    req.on('close', () => {
      clearInterval(interval);
      res.end();
    });
  } else {
    res.writeHead(404);
    res.end('Not found');
  }
});

server.listen(3000, () => {
  console.log('SSE server running on http://localhost:3000');
});

Understanding the SSE Format

The SSE protocol requires data to be formatted in a specific way:

  • Event data: Each message must be prefixed with data:
  • Line breaks: Messages must end with two newline characters \n\n
  • JSON serialization: Object data should be serialized to JSON before sending
  • Connection headers: Proper headers maintain the connection

Client-Side Implementation

On the client side, you'll use the EventSource API to connect to the SSE endpoint and receive messages.

Basic EventSource Setup

// Create EventSource connection
const eventSource = new EventSource('/sse-endpoint');

// Handle incoming messages
eventSource.onmessage = function(event) {
  const data = JSON.parse(event.data);
  console.log('Received:', data);
  
  // Display the data in your UI
  displayUpdate(data);
};

// Handle connection open
eventSource.onopen = function(event) {
  console.log('SSE connection opened');
};

// Handle errors
eventSource.onerror = function(event) {
  console.error('SSE error:', event);
};

// Close connection when done
function closeConnection() {
  eventSource.close();
}

Handling Different Event Types

SSE supports custom event types for organizing different streams of data:

// Server: Send custom event type
res.write('event: user-update\n');
res.write('data: ' + JSON.stringify({ userId: 123, name: 'John' }) + '\n\n');

// Client: Listen for specific event type
eventSource.addEventListener('user-update', function(event) {
  const data = JSON.parse(event.data);
  updateUserProfile(data);
});

Advanced SSE Patterns

Here are some advanced patterns for working with SSE and JSON:

Managing Multiple Connections

const connections = new Set();

const server = http.createServer((req, res) => {
  if (req.url === '/sse-endpoint') {
    res.writeHead(200, {
      'Content-Type': 'text/event-stream',
      'Cache-Control': 'no-cache',
      'Connection': 'keep-alive'
    });

    connections.add(res);

    req.on('close', () => {
      connections.delete(res);
    });
  }
});

// Broadcast to all connected clients
function broadcast(data) {
  const message = 'data: ' + JSON.stringify(data) + '\n\n';
  connections.forEach(client => {
    client.write(message);
  });
}

Error Handling and Reconnection

Automatic Reconnection

The EventSource API automatically attempts to reconnect if the connection is lost. You can customize the reconnection behavior using the retry field in your SSE messages.

// Server: Set retry interval
res.write('retry: 3000\n\n');

// Client: Handle reconnection events
eventSource.addEventListener('error', function(event) {
  if (eventSource.readyState === EventSource.CONNECTING) {
    console.log('Reconnecting...');
  } else if (eventSource.readyState === EventSource.CLOSED) {
    console.log('Connection closed');
    // Manually reconnect or show error
  }
});

SSE vs WebSockets vs Polling

Understanding when to use SSE versus other real-time communication methods:

TechnologyCommunicationBest Use Case
SSEUnidirectional (Server to Client)Real-time feeds, notifications, live updates
WebSocketBidirectionalChat applications, gaming, collaborative editing
PollingClient requestsSimple updates, compatibility fallback

Best Practices

Use JSON Validation

Always validate JSON data on both server and client to prevent parsing errors and security issues.

Implement Connection Limits

Limit the number of concurrent SSE connections per user to prevent server resource exhaustion.

Close Connections Properly

Always clean up connections and intervals when clients disconnect to free up server resources.

Real-World Example: Live JSON Data Stream

Here's a complete example of streaming JSON data from a Node.js server to a client:

// Server: app.js
const http = require('http');
const url = require('url');

const server = http.createServer((req, res) => {
  const parsedUrl = url.parse(req.url, true);

  if (parsedUrl.pathname === '/stream') {
    res.writeHead(200, {
      'Content-Type': 'text/event-stream',
      'Cache-Control': 'no-cache',
      'Connection': 'keep-alive',
      'Access-Control-Allow-Origin': '*'
    });

    let counter = 0;

    const interval = setInterval(() => {
      const jsonData = {
        id: counter++,
        timestamp: new Date().toISOString(),
        data: {
          temperature: Math.floor(Math.random() * 30) + 20,
          humidity: Math.floor(Math.random() * 40) + 30
        }
      };

      res.write('data: ' + JSON.stringify(jsonData) + '\n\n');
    }, 2000);

    req.on('close', () => {
      clearInterval(interval);
    });
  } else {
    res.writeHead(404);
    res.end('Not found');
  }
});

server.listen(3000);

// Client: index.html
<!DOCTYPE html>
<html>
<head>
  <title>SSE Example</title>
</head>
<body>
  <div id="output"></div>
  <script>
    const source = new EventSource('http://localhost:3000/stream');
    
    source.onmessage = function(event) {
      const data = JSON.parse(event.data);
      document.getElementById('output').innerHTML += 
        '<p>ID: ' + data.id + ', Temp: ' + data.data.temperature + '°C</p>';
    };
  </script>
</body>
</html>

Conclusion

Server-Sent Events provide an excellent solution for streaming real-time data from server to client. Combined with JSON, SSE offers a simple and efficient way to implement live updates in web applications.

SSE is particularly well-suited for applications where the server needs to push updates to clients, such as live feeds, notifications, progress indicators, and real-time dashboards. The automatic reconnection feature and simple EventSource API make it easy to implement robust real-time communication.

Need to Format Your JSON First?

Use our free JSON formatter to validate and format your JSON data before streaming it through Server-Sent Events. Ensure your JSON is properly structured and error-free.

Try JSON Formatter