In the post learn to build Streaming APIs with Server-Sent Events (SSE) in Spring WebFlux for efficient one-way communication to browsers or clients.

📑 Table of Contents
- What Are Server-Sent Events?
- SSE vs WebSockets vs Polling
- Why Use SSE in Reactive APIs?
- Adding SSE Support in Spring WebFlux
- Implementing an SSE Endpoint
- Consuming SSE in the Browser
- Keeping SSE Connections Alive
- Error Handling & Retry in SSE
- Production Considerations
- Final Thoughts
🔄 1. What Are Server-Sent Events?
Server-Sent Events (SSE) are a unidirectional communication mechanism where the server pushes updates to the client over HTTP. They use the text/event-stream
content type and are part of the HTML5 standard.
Unlike WebSockets, SSE is simpler, requires no special protocol, and works over standard HTTP/1.1.
⚔️ 2. SSE vs WebSockets vs Polling
Feature | SSE | WebSockets | Polling |
---|---|---|---|
Direction | Server → Client (One-way) | Bi-directional | Client → Server (repeated) |
Protocol | HTTP | Custom TCP (ws://) | HTTP |
Simplicity | Very simple | Complex | Very simple |
Browser Support | Excellent (all modern) | Good (requires JS libs) | Excellent |
Use Case | Stock Tickers, Notifications | Chat, Games | Fallback, low updates |
⚡ 3. Why Use SSE in Reactive APIs?
Spring WebFlux shines when combined with SSE:
- Native support for
text/event-stream
- Easily returns
Flux<T>
directly from controller - Uses Reactor’s backpressure model
- Perfect for notifications, sensor data, logs, etc.
🧱 4. Adding SSE Support in Spring WebFlux
Ensure you have this dependency:
1 2 3 4 5 6 7 8 |
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-webflux</artifactId> </dependency> |
Spring WebFlux automatically supports SSE when you return a Flux<T>
and set the response type to MediaType.TEXT_EVENT_STREAM
.
👨💻 5. Implementing an SSE Endpoint
Here’s a simple example that emits a stream of numbers every second:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
package com.kscodes.springboot.reactive.controller; import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import reactor.core.publisher.Flux; import java.time.Duration; @RestController public class SseController { @GetMapping(value = "/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE) public Flux<String> streamData() { return Flux.interval(Duration.ofSeconds(1)) .map(seq -> "Event " + seq); } } |
🧠 How It Works:
- The controller returns a
Flux<String>
- Spring serializes it as
text/event-stream
- The browser keeps the connection open and renders each line as an event
🌐 6. Consuming SSE in the Browser
JavaScript Example:
1 2 3 4 5 6 7 8 9 |
< script> const eventSource = new EventSource("http://localhost:8080/stream"); eventSource.onmessage = function (event) { console.log("New event:", event.data); }; < /script> |
✅ Works in all modern browsers including Chrome, Firefox, Safari, and Edge.
♻️ 7. Keeping SSE Connections Alive
Most proxies and load balancers kill idle connections. To prevent that:
- Send heartbeat events every few seconds:
1 2 3 4 5 |
Flux.interval(Duration.ofSeconds(10)) .map(i -> "heartbeat - " + i); |
Use Cache-Control: no-transform
and Connection: keep-alive
headers if needed
🛠️ 8. Error Handling & Retry in SSE
SSE supports built-in retry behavior.
You can add retry
time and id
:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
@GetMapping(value = "/events", produces = MediaType.TEXT_EVENT_STREAM_VALUE) public Flux<ServerSentEvent<String>> events() { return Flux.interval(Duration.ofSeconds(1)) .map(seq -> ServerSentEvent.<String>builder() .id(String.valueOf(seq)) .event("message") .data("Update " + seq) .retry(Duration.ofSeconds(5)) .build()); } |
This enables the browser to resume automatically on disconnects.
🚀 9. Production Considerations
- Timeouts: Configure reverse proxies like NGINX to allow long-lived connections
- Load Balancing: Sticky sessions or consistent hashing might be required
- Security: Add headers like
X-Accel-Buffering: no
to prevent buffering by proxies - Monitoring: SSE endpoints are stateful—monitor active connections
✅ 10. Final Thoughts
Server-Sent Events offer a lightweight way to stream real-time data to the browser using Spring WebFlux and Flux
. It’s ideal for use cases that don’t require two-way communication but need frequent updates — like logs, live notifications, system metrics, or IoT data.