🌐 Handling 1 Million WebSocket Connections in Spring Boot (Without Losing My Mind)
WebSockets are amazing for real-time apps (chat, notifications, gaming, live dashboards). But handling 1M concurrent connections sounds insane, right?
With the right approach, Spring Boot + Java can scale to millions of persistent connections. Let’s see how.
🚀 The Challenge
Each WebSocket connection:
- Holds a TCP socket open
- Consumes memory for buffers
- Needs threads for read/write
If you try this with traditional blocking I/O (Servlet) → 💥 your server dies.
So how do we survive?
🛠 Step 1: Use Spring WebFlux (Reactive)
Spring MVC (Servlet-based) isn’t built for millions of concurrent sockets.
Switch to Spring WebFlux (reactive + non-blocking).
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>🛠 Step 2: Create a Reactive WebSocket Handler
@Component
public class ChatSocketHandler implements WebSocketHandler {
@Override
public Mono<Void> handle(WebSocketSession session) {
return session.send(
session.receive()
.map(msg -> "Echo: " + msg.getPayloadAsText())
.map(session::textMessage)
);
}
}🛠 Step 3: Register the WebSocket Endpoint
@Configuration
@EnableWebFlux
public class WebSocketConfig implements WebSocketConfigurer {
private final ChatSocketHandler handler;
public WebSocketConfig(ChatSocketHandler handler) {
this.handler = handler;
}
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(handler, "/ws/chat")
.setAllowedOrigins("*");
}
}🛠 Step 4: Tune the JVM & Netty
Since WebFlux runs on Netty, tweak resources:
# application.properties
spring.main.reactive-web-server=netty
spring.netty.leak-detection=paranoidJVM tuning (example for 8GB RAM server):
java -Xms4g -Xmx4g -XX:+UseG1GC -jar app.jar🛠 Step 5: Scale Horizontally with Load Balancing
No single server will handle 1M connections reliably.
Instead:
- Run 10 servers × 100k connections each
- Put NGINX, HAProxy, or Envoy in front
NGINX example:
http {
upstream websocket_backend {
server app1:8080;
server app2:8080;
server app3:8080;
}
---
server {
listen 80;
location /ws/ {
proxy_pass http://websocket_backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
}
🛠 Step 6: Manage State (Pub/Sub)
Since clients are spread across servers, you need a message broker for broadcasting.
Get Lakshika’s stories in your inbox
Join Medium for free to get updates from this writer.
Popular choices:
- Redis Pub/Sub
- Kafka
- RabbitMQ
Example:
@EventListener
public void handleMessage(BroadcastEvent event) {
sessions.forEach(session -> session.send(
Mono.just(session.textMessage(event.getMessage())))
);
}⚡ Real-World Lessons
- Reactive > Threads → Use WebFlux, not Servlet.
- Load Balance → 1M connections across multiple servers.
- State Sharing → Use Redis/Kafka for distributed messaging.
- Backpressure → Always handle slow clients gracefully.
🎯 Final Thoughts
1M WebSocket connections isn’t about writing crazy Java code.
It’s about:
- Choosing reactive architecture
- Optimizing the JVM + Netty
- Scaling horizontally with load balancing + message brokers
Spring Boot + WebFlux + Redis = a battle-tested way to handle real-time apps at scale.
👉 If you’re building chat apps, live dashboards, multiplayer games, or trading systems, this setup will keep you sane.
A message from our Founder
Hey, Sunil here. I wanted to take a moment to thank you for reading until the end and for being a part of this community.
Did you know that our team run these publications as a volunteer effort to over 3.5m monthly readers? We don’t receive any funding, we do this to support the community. ❤️
If you want to show some love, please take a moment to follow me on LinkedIn, TikTok, Instagram. You can also subscribe to our weekly newsletter.
And before you go, don’t forget to clap and follow the writer️!










