A production-ready Server-Sent Events toolkit for Spring Boot & Angular
Build real-time, event-driven applications with first-class SSE support on both server and client. Zero boilerplate. Production-grade. Horizontally scalable.
Server Docs · Client Docs · Redis Bridge · Cloud Stream Bridge · Samples
| Package | Description | Language |
|---|---|---|
sse-server |
Reactive SSE emitter with auto-configuration, topic management, heartbeat, CORS, metrics & more | Java / Spring Boot |
sse-server-bridge-redis |
Multi-pod event fan-out via Redis Pub/Sub — just add the dependency, zero config | Java / Spring Data Redis |
sse-server-bridge-cloud-stream |
Multi-pod event fan-out via Kafka, RabbitMQ, Google Pub/Sub, or any Spring Cloud Stream binder | Java / Spring Cloud |
ng-sse-client |
Typed, zone-aware SSE client with auto-reconnect, backoff & jitter | TypeScript / Angular |
sse-sample-server-app |
Runnable Spring Boot sample emitting periodic events | Java |
ng-sse-client-app |
Angular sample app consuming an SSE stream | TypeScript |
- Zero-config SSE endpoints — auto-configured functional router at
GET /sse/{topic} - Topic-based pub/sub — emit to specific topics or broadcast to all
- Built-in heartbeat — keeps connections alive through proxies and load balancers
- Session tracking — lifecycle hooks for connect/disconnect events
- Flexible serialization — pluggable
EventSerializerfor custom payload encoding - MDC propagation — bridge Reactor context to MDC for structured logging
- CORS support — auto-configured, scoped to SSE endpoints
- Micrometer metrics — emit/subscribe/error counters with optional per-topic labels
- RFC 7807 errors — structured
application/problem+jsonerror responses - Configurable backpressure — choose MULTICAST or REPLAY sinks with tunable buffer sizes
- Redis bridge — add one dependency for instant multi-pod support via Redis Pub/Sub
- Cloud Stream bridge — use Kafka, RabbitMQ, Google Pub/Sub, Pulsar, or Azure Event Hubs
- Zero custom code — auto-configured bridges, just add a dependency
- Self-deduplication — instance-aware filtering prevents echo loops
- Two options — lightweight Redis or full Spring Cloud Stream binder ecosystem
- Strongly-typed streams — generic
parsehook for compile-time safety - Smart reconnection — exponential backoff with jitter, configurable limits
- Zone-optimized — runs outside Angular zone, re-enters on emissions for performance
- Named events — subscribe to specific SSE event types
- Last-Event-ID — automatic propagation for resumable streams
1. Add the dependency
<dependency>
<groupId>com.spectrayan.sse</groupId>
<artifactId>sse-server</artifactId>
<version>2.0.0</version>
</dependency>2. Emit events from your service
@Service
@RequiredArgsConstructor
public class NotificationService {
private final SseEmitter emitter;
public void notifyUser(String userId, Notification notification) {
emitter.emit(userId, "notification", notification);
}
public void broadcastAlert(Alert alert) {
emitter.emit(alert); // sends to all connected topics
}
}3. Clients connect to the auto-configured endpoint
GET http://localhost:8080/sse/my-topic
Accept: text/event-stream
That's it — no controllers, no routers, no configuration needed. The library auto-configures everything.
npm install @spectrayan/ng-sse-clientimport { SseClient } from '@spectrayan/ng-sse-client';
@Component({ /* ... */ })
export class DashboardComponent {
private sse = inject(SseClient);
notifications$ = this.sse.stream<Notification>('/sse/notifications', {
parse: (raw) => JSON.parse(raw),
reconnect: true,
});
}SSE is inherently stateful — connections are held in-memory on one server. In multi-pod deployments, events emitted on Pod A won't reach clients on Pod B.
Choose your bridge — both require zero custom code:
<!-- One dependency — that's it -->
<dependency>
<groupId>com.spectrayan.sse</groupId>
<artifactId>sse-server-bridge-redis</artifactId>
<version>2.0.0</version>
</dependency>spring:
data:
redis:
host: localhost
port: 6379<dependency>
<groupId>com.spectrayan.sse</groupId>
<artifactId>sse-server-bridge-cloud-stream</artifactId>
<version>2.0.0</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-binder-kafka</artifactId> <!-- or -rabbit, etc. -->
</dependency>spring:
cloud:
function:
definition: sseBridgeConsumer
stream:
bindings:
sseBridgeConsumer-in-0:
destination: sse-broadcast
group: ${spring.application.name}📖 Full Cloud Stream bridge guide →
flowchart LR
subgraph PodA["Pod A"]
A1["SSE Clients"]
A2["emit(topic, data)"]
end
subgraph Broker["Redis / Kafka / RabbitMQ / Pub/Sub"]
B1["sse-broadcast channel"]
end
subgraph PodB["Pod B"]
B2["SSE Clients"]
end
A2 -- publish --> B1
B1 -- deliver --> PodB
PodB -- publish --> B1
B1 -- deliver --> PodA
flowchart TD
subgraph App["Your Application"]
Emitter["SseEmitter\n(emit / broadcast)"] --> ES["EmissionService\n(local sink + bridge)"]
ES --> Bridge["SseBroadcastBridge\n(fan-out to other instances)"]
Emitter --> TM["TopicManager\n(per-topic Reactor sinks)"]
ES --> SC["StreamComposer\n(heartbeat + connected + error mapping)"]
Bridge --> Impl["NoOpBroadcastBridge\nor RedisBridge\nor CloudStreamBridge"]
end
Prerequisites: Node.js 20+, Java 21, Maven 3.9+, Git
# Clone and setup
git clone https://github.com/spectrayan/server-sent-events.git
cd server-sent-events
make setup # npm ci
# Build & test everything
make ci # Angular build/test + Maven verify
# Or individually
make build-ng # Angular library only
make verify-mvn # Java libraries only
make clean # Clean all build artifacts| Library | README | Install |
|---|---|---|
| sse-server | 📖 Docs | Maven Central |
| sse-server-bridge-redis | 📖 Docs | Maven Central |
| sse-server-bridge-cloud-stream | 📖 Docs | Maven Central |
| ng-sse-client | 📖 Docs | npm |
| Sample | Description | Run |
|---|---|---|
sse-sample-server-app |
Spring Boot app emitting periodic events | mvn spring-boot:run |
ng-sse-client-app |
Angular app consuming SSE stream | ng serve |
📋 Releasing (Maintainers)
We follow a Spring-inspired versioning lifecycle for the Java libraries:
| Stage | Example | Target | Profile |
|---|---|---|---|
| SNAPSHOT | 2.1.0-SNAPSHOT |
OSSRH Snapshots | -P snapshot |
| Milestone | 2.1.0-M1 |
Maven Central | -P milestone |
| Release Candidate | 2.1.0-RC1 |
Maven Central | -P rc |
| GA / Release | 2.1.0 |
Maven Central | -P release |
Angular packages follow standard npm semver and publish via Git tags.
- GPG key — generate with
gpg --full-generate-key(RSA 4096-bit) - Maven
settings.xml— configurecentralandossrh-snapshotsservers - Environment variables:
GPG_PASSPHRASE,CENTRAL_USERNAME,CENTRAL_PASSWORD,OSSRH_USERNAME,OSSRH_PASSWORD - Clean Git state — on
main, no uncommitted changes
# Snapshot (can be overwritten)
mvn -P snapshot -DskipTests=false clean deploy
# Milestone / RC / GA release
mvn -P release \
release:prepare release:perform \
-DreleaseVersion=2.0.0 \
-DdevelopmentVersion=2.0.1-SNAPSHOT \
-DlocalCheckout=true -DupdateWorkingCopyVersions=false -DpushChanges=false| Workflow | Trigger | What it does |
|---|---|---|
libs-release.yml |
Push to main / manual |
Build + test all, auto-publish to GitHub Packages |
libs-snapshot.yml |
Manual | Deploy SNAPSHOT to Maven Central |
libs-milestone.yml |
Manual (with inputs) | Milestone / RC / GA release to Maven Central |
npm run build ng-sse-client
(cd dist/libs/ng-sse-client && npm publish --access public)We welcome contributions! Please read:
CONTRIBUTING.md— how to contributeCODE_OF_CONDUCT.md— community guidelinesSECURITY.md— reporting security vulnerabilities
This project is licensed under the Apache License 2.0.
Questions, issues, or feedback: support@spectrayan.com