A Complete Developer’s Guide with Node.js, React, React Native, and Next.js
🧠 1. What is Server-Sent Events (SSE)?
Server-Sent Events (SSE) is a unidirectional streaming protocol built into modern browsers. It allows servers to push real-time updates to the client over a single long-lived HTTP connection using the EventSource
API.
Think of it as a reverse
fetch
—once initiated, the server keeps sending data as events happen.
🔑 Key Characteristics
- Built on HTTP/1.1 (no WebSocket upgrade needed)
- Text/event-stream content type
- Auto-reconnect mechanism by the browser
- Low overhead, lightweight, easy to implement
🎯 2. When to Use SSE?
SSE shines in server-to-client real-time delivery scenarios, especially where simplicity and HTTP compatibility are key.
🔧 Common Use Cases
Use Case | Why SSE Fits Well |
---|---|
🔔 Notifications | Push updates to logged-in users instantly |
📊 Live Dashboards | Periodic updates to analytics or KPIs |
📰 Real-Time News Feeds | Auto-refreshing breaking news |
⏱️ Tickers & Clocks | Update countdowns or current time |
📡 IoT Device Updates | Sensor streams without bidirectional need |
⚠️ Use WebSocket when you require two-way communication (e.g. chat, multiplayer games).
⚙️ 3. How SSE Works
📤 Server Response
HTTP/1.1 200 OK Content-Type: text/event-stream Cache-Control: no-cache Connection: keep-alive
Each message sent must:
- Start with
data:
and end with two newlines - Optionally include:
id:
,event:
,retry:
🔁 Message Format
data: {"message":"Hello, client!"} data: {"time":"2025-08-02T12:00:00Z"}
🧪 Basic JavaScript Client
const es = new EventSource("http://localhost:4000/events"); es.onmessage = (event) => { const data = JSON.parse(event.data); console.log("Received:", data); }; es.onerror = () => { console.warn("Connection lost. Reconnecting..."); };
🛠️ 4. Node.js Express SSE Server Example
const express = require("express"); const cors = require("cors"); const app = express(); app.use(cors()); app.get("/events", (req, res) => { res.setHeader("Content-Type", "text/event-stream"); res.setHeader("Cache-Control", "no-cache"); res.setHeader("Connection", "keep-alive"); const send = () => { const payload = JSON.stringify({ time: new Date().toISOString() }); res.write(`data: ${payload}\n\n`); }; send(); // Send initial data immediately const interval = setInterval(send, 5000); req.on("close", () => { clearInterval(interval); console.log("Cleanup: Client disconnected"); }); }); app.listen(4000, () => console.log("SSE server running on port 4000"));
✅ Tip: Add
res.flush()
if usingcompression
middleware (to push chunks immediately).
💻 5. SSE Clients
🌐 React (Web)
import { useEffect, useState } from "react"; export default function SSEComponent() { const [time, setTime] = useState(""); useEffect(() => { const es = new EventSource("http://localhost:4000/events"); es.onmessage = (e) => { const data = JSON.parse(e.data); setTime(data.time); }; es.onerror = () => { console.warn("SSE connection error"); }; return () => es.close(); }, []); return <div>Server Time: {time}</div>; }
📱 React Native (Mobile)
npm install react-native-event-source
Alternative Packages:
- https://www.npmjs.com/package/react-native-sse
- https://www.npmjs.com/package/@ammarahmed/react-native-eventsource
import EventSource from "react-native-event-source"; import { useEffect } from "react"; export default function LiveStream() { useEffect(() => { const es = new EventSource("http://192.168.1.x:4000/events"); es.onmessage = (event) => { console.log("Data:", event.data); }; return () => es.close(); }, []); return null; }
⚠️ Use IP instead of
localhost
and ensure both devices are on the same network.
⛓️ Next.js (Client Component)
"use client"; import { useEffect, useState } from "react"; export default function Page() { const [data, setData] = useState(""); useEffect(() => { const es = new EventSource("/api/events"); es.onmessage = (e) => { setData(JSON.parse(e.data).time); }; return () => es.close(); }, []); return <div>Time: {data}</div>; }
🧪 Next.js API Route (SSE Handler)
export function GET(req: Request) { const encoder = new TextEncoder(); const stream = new ReadableStream({ start(controller) { const interval = setInterval(() => { const data = `data: ${JSON.stringify({ time: new Date().toISOString(), })}\n\n`; controller.enqueue(encoder.encode(data)); }, 5000); req.signal.addEventListener("abort", () => { clearInterval(interval); controller.close(); }); }, }); return new Response(stream, { headers: { "Content-Type": "text/event-stream", "Cache-Control": "no-cache", Connection: "keep-alive", }, }); }
🔍 6. Advanced SSE Features
Custom Event Types
res.write("event: customEvent\n"); res.write(`data: {"message":"Custom event triggered!"}\n\n`);
es.addEventListener("customEvent", (e) => { console.log("Custom Event:", e.data); });
Retry Delay Control
retry: 10000 data: {"message":"Retry in 10s"}
Client waits 10 seconds before reconnecting.
⚖️ 7. Pros and Cons
✅ Pros
- Native browser API (
EventSource
) - No third-party library needed
- Simple, scalable (good for thousands of clients)
- Works well with HTTP infrastructure
❌ Cons
- One-way only
- Not supported in all mobile environments (needs polyfill)
- Needs proxy tweaks (e.g., Cloudflare, Nginx)
- No binary or structured message formats (text-only)
🔄 8. SSE vs WebSocket
Feature | SSE | WebSocket |
---|---|---|
Direction | Server ➡️ Client | Bidirectional |
Protocol | HTTP/1.1 | WS (Upgrade from HTTP) |
Browser Support | Most browsers | All modern browsers |
Complexity | Low | Medium–High |
Streaming | Text-only | Binary, JSON, Text |
Mobile Support | Polyfill required | Native |
Reconnect | Built-in basic retry | Manual handling required |
🧱 9. Production Considerations
- ✅ Disable compression middleware to prevent buffered messages
- ✅ Turn off proxy buffering (e.g., Nginx)
location /events { proxy_pass http://localhost:4000; proxy_buffering off; chunked_transfer_encoding off; }
- ✅ Use heartbeats (e.g.,
data:\n\n
) to keep connections alive - ✅ Reconnection logic: Use
es.onerror
ores.readyState
checks
🔄 10. Alternatives
Tech | Direction | Transport |
---|---|---|
WebSocket | Two-way | WebSocket |
Socket.IO | Two-way + fallback | WebSocket, polling |
GraphQL Subscriptions | Two-way (GraphQL) | WebSocket |
Firebase | Two-way | Proprietary |
Pusher / Ably | Pub/Sub | WebSocket / HTTP |
Kafka REST Proxy | One-way stream | HTTP/REST |
✅ 11. Conclusion
Server-Sent Events are a lightweight, simple, and scalable way to stream real-time data from server to client using nothing but HTTP and vanilla JavaScript.
They’re a perfect fit for dashboards, notifications, live feeds, and IoT monitoring—especially when you don’t need two-way communication.
Use SSE when simplicity and scalability matter. Use WebSocket when interaction matters.
Top comments (0)