The Age of Real-Time Apps <>
While exploring and experimenting with Spring Web Flux, I stumbled upon an interesting feature called Server-Sent Events (SSE) (rather an HTML5 standard) . Although I haven’t had the opportunity to use SSE in my professional projects yet, it immediately caught my attention — both for how it works and the real-time advantages it offers. I was curious to understand where it fits as a component within a modern, real-time application architecture. Here’s a summary of my key learnings and hands-on experience while experimenting with it.
Every day we see many real time applications where stock prices changing every second, live cricket scores updating ball by ball, chat notifications popping instantly, and dashboards refreshing in real-time. Just a decade ago, these features were cutting-edge, but today, they’re the new normal.
Traditionally, web applications followed a simple request-response model:
- The client (browser) asks for data.
- The server responds.
- And then render on the client side.
If you wanted new data, you had to ask again — the infamous polling mechanism. But what if the server could push updates to the client automatically without waiting for another request ? that is why we SSE comes in to the picture
Server-Sent Events (SSE)?
Server-Sent Events is a standard in HTML5. It is a mechanism of pushing updates from the server side to the client, over an HTTP connection. Unlike web sockets (bi-directional) or polling , SSE provides a sweet spot for unidirectional event streams—think notifications and live feeds, not chat or games.
- The client (typically a browser or JavaScript client) opens a connection to a specific endpoint using
EventSource. - The server keeps that connection open and continuously pushes new data whenever it’s available.
- The client listens for messages and updates the UI or state accordingly.
It’s a unidirectional flow — server → client, not the other way around.
Here’s what it looks like visually:
Browser (EventSource) ───────▶ Spring WebFlux SSE Endpoint
Why SSE Over WebSockets or Polling?
let’s quickly understand where SSE fits , Polling, Long Polling, and WebSockets.
- SSE: Best for unidirectional data streams—notifications, tickers, logs.
- WebSockets: Best for bidirectional communication like collaborative tools, chat apps, or online gaming.
- Polling/Long Polling: Inefficient for high-frequency updates but simple to implement if event frequency is low.
| Technique | Direction | Complexity | Scalability | Ideal Use Case |
|---|---|---|---|---|
| Polling | Client → Server repeatedly | Simple | Poor (many requests) | Low frequency updates |
| Long Polling | Client waits longer for response | Moderate | Better than polling | Medium-frequency updates |
| WebSockets | Bidirectional | Complex | Excellent | Chat, gaming, live collaboration |
| SSE | Server → Client | Simple | Good (HTTP-based) | Live feeds, dashboards, notifications |
Why SSE Fits Perfectly in Spring WebFlux
Spring WebFlux is all about non-blocking, reactive programming. Its foundation lies on Project Reactor, which provides reactive streams (Flux, Mono, Publisher, etc.) that handle data asynchronously.
Now here’s the magic — SSE aligns beautifully with the reactive model because both rely on streams of data that arrive over time. A Flux in WebFlux can emit multiple elements — just like an SSE connection streams multiple events.
SSE fits seamlessly into the reactive paradigm, imagine your backend emits a stream of updates from a database, a message broker, or some internal event pipeline, and you want to deliver those to the client directly. Done right, threading, resource utilization, and latency are all optimized.
Architecture Overview
Let’s visualize how SSE fits into a Spring Web Flux system:
┌───────────────────────┐
│ Browser │
│ EventSource API │
│ (SSE client) │
└──────────┬────────────┘
│
HTTP Request
│
┌──────────▼────────────┐
│ Spring WebFlux App │
│ @GetMapping("/stream")│
│ returns Flux<Event> │
└──────────┬────────────┘
│
Reactive Stream
│
┌──────────▼────────────┐
│ Service / Reactor │
│ Emits continuous data│
└───────────────────────┘
s long as the connection remains open, the browser keeps receiving new events — all handled asynchronously and efficiently.
Real backend requirements:
- Push real domain events : Suppose you want to push updates from a messaging system (like RabbitMQ or Kafka) as SSE to all connected clients. The key insight: use Spring’s reactive types such as
FluxSinkand process data reactively as it arrives. - Support multiple event types : (custom event names)
- Handle client disconnects and retries
- Clients can disconnect at any point—network issues, user actions, browser closes. Design your system not to leak resources. With the
onDisposehook (see above), each listener (connection) is cleaned up immediately on disconnect. - Backpressure
- Spring WebFlux’s reactive types are built to handle backpressure. If a client can’t keep up, the server only buffers what’s needed and doesn’t block threads, making it scalable to thousands of open streams.
- Automatic Reconnections
- The default EventSource implementation in browsers auto-reconnects if the server goes down or their WiFi glitches. You don’t need to handle this at the server, but if you want to restore missed messages after a reconnect, use the SSE
id:field. The client’s EventSource will send aLast-Event-IDheader to let your server know what was last received.
- The default EventSource implementation in browsers auto-reconnects if the server goes down or their WiFi glitches. You don’t need to handle this at the server, but if you want to restore missed messages after a reconnect, use the SSE
- Clients can disconnect at any point—network issues, user actions, browser closes. Design your system not to leak resources. With the
- Optimal resource usage under load
- Spring WebFlux relies on Netty (by default), enabling thousands of open connections with low resource usage. Some proxies or firewalls drop idle HTTP connections. To defend against dropouts, send periodic heartbeat events.
Common Use Cases for SSE
- Real-time dashboards – CPU usage, analytics, IoT data.
- Live news or stock tickers (Stock Trading Platforms).
- System monitoring alerts.
- Progress tracking for long-running jobs.
- Monitoring Dashboards: Server metrics, logs, alerts pushed as events
- News Feeds & Push Notifications: Personalized event streams in B2C apps
- IoT & Sensor Networks: Stream data back from devices to user dashboards
Scaling SSE in Production
When scaling SSE endpoints:
- Use Spring WebFlux + Netty (non-blocking).
- Deploy behind load balancers that support persistent connections (e.g., Nginx).
- Configure appropriate idle timeouts and connection limits.
- For global scale, consider Redis pub/sub or Kafka streams as message backplanes.
Limitations of SSE
Let’s be honest — SSE isn’t a silver bullet.
| Limitation | Description |
|---|---|
| One-way communication | Client cannot send messages back (use WebSockets if needed). |
| No binary data | Only test based messages |
| Browser support | Great for modern browsers, but not supported in very old versions. |
| Connection limits | Limits set by each browser on the number of open SSE connections |
But for most real-time notification scenarios, SSE remains elegant and efficient.
Best Practices
- Keep payloads lightweight.
SSE is text-based — avoid sending bulky data frequently. - Use
ServerSentEventfor structured messages.
It helps withid,event, andretryfields. - Gracefully handle errors — always listen to
onerroron the client. - Leverage
Fluxoperators (e.g.,filter,map,flatMap) to transform streams reactively. - Secure SSE endpoints — use authentication or JWTs if required.
Conclusion:
In a world of microservices, reactive systems, and live experiences, Server-Sent Events offer a lightweight and elegant solution for real-time, one-way data streaming.
When combined with Spring WebFlux, SSE becomes:
- Easy to implement
- Non-blocking and scalable
- Seamlessly integrated with reactive data pipelines
Whether it’s a live dashboard, stock tracker, or notification feed — SSE in WebFlux helps you bridge the gap between backend events and user experiences effortlessly.
So next time you need a “live update” in your app —
Think simple. Think streaming. Think Server-Sent Events with Spring WebFlux.