Every developer building a chat app eventually stumbles into the same rabbit hole: Do I use WebSockets or Server-Sent Events (SSE)? It sounds like a minor technical choice at first—just pick whichever tutorial looks nicer on YouTube and move on. But trust me, this one decision can quietly shape the scalability, complexity, and sanity of your project (and your future AWS bills if you pick wrong).
When I started working on real-time communication for my Django app, I had to make this exact decision. The app needed chat, but chat wasn’t the main feature just a nice to have. So naturally I didn't wnat to spend more time on selecting techonlogies and give it a whole new timeline.
In this article, we’ll dive deep into what real-time communication really is, explore how SSE and WebSockets work, compare them side by side, and finally, I’ll share why I picked SSE for my project (and why it was some sort of inspired by linkedin).
Deep Dive into SSE
How It Works
Sever Sent Events (SSE) is like an open door which the client makes to the server the open door only allows one way communication from server to the client not the other way around it sends messages its just another TCP connection which just has its end packet forgotten so it keeps on going.
It’s built on plain old HTTP, so you don’t need to break your brain setting up new protocols.
Code Example: SSE in Django
Server (Django view):
from django.http import StreamingHttpResponse
import time
def sse_chat_stream(request):
def event_stream():
while True:
# In reality, pull from Redis/pub-sub
yield f"data: New message at {time.time()}\n\n"
time.sleep(2)
return StreamingHttpResponse(event_stream(), content_type='text/event-stream')
Client (JavaScript):
const eventSource = new EventSource("/chat/stream/");
eventSource.onmessage = function(event) {
console.log("New message:", event.data);
};
That’s it. You’ve got a real-time connection with about 20 lines of code. (Which is about 50 fewer than WebSockets usually require.)
Pros of SSE
- Simple and easy to impliment with very less of a overhaul.
- One way communication mostly realtime but this can become a down side too
- Your browser autoretrys the connection in an event of failure
- Almost all browsers support it (Almost is due to IE)
Cons of SSE
- So one way communication is also pro but can be a con depending on your project.
- Not great if your app relies on the milisecond the message is sent you have to recieve it
- No binary data (text only). If you need binary, look elsewhere. but can be useful
But here’s the kicker: for 80% of “real-time” needs—like chats that aren’t the entire focus of the product—SSE is more than enough you don't need NASA like communication that every millisecond matters.
Deep Dive into WebSockets
How It Works
WebSockets are like having a direct phone line between client and server. Once connected, both can talk freely, as much as they want, whenever they want, just a private, always-on conversation.
It’s a separate protocol that starts with an HTTP handshake and then upgrades to a persistent TCP connection.
Code Example: WebSockets
Server (Node.js with ws*):*
const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8080 });
wss.on('connection', ws => {
ws.on('message', message => {
console.log(`Received: ${message}`);
ws.send(`Echo: ${message}`);
});
});
Client:
const socket = new WebSocket("ws://localhost:8080");
socket.onopen = () => socket.send("Hello Server");
socket.onmessage = event => console.log(event.data);
Now you’ve got two-way communication—chat, games, collaborative docs, you name it.
Pros of WebSockets
- Both ways of communication can happen any time.
- Latency is very low almost realtime
- Perfect for chat apps if your main focus is reducing latency to the 10th of a second
- Binary data handling is supported.
Cons of WebSockets
- Complex to scale and has lots of network limitations
- Requires extra setup in case of django it can be another level of headache
- Its too powerful for simple apps and comes with the same cost.
My Real-World Implementation
Here’s the context: I was building a Django app where chat was a nice-to-have feature, not the core. Think of it as the beverages that come in a Burger King combo not needed but good to have. (Yes I don't like soft drinks that much)
I first considered WebSockets. They’re the gold standard for chat, after all. But as I dug deeper, I realized setting up Django Channels, handling scaling with Redis, configuring sticky sessions, and then debugging it all would be like bringing a rocket launcher to open a soda can.
Then I started researching more on the topic and did some reverse engineering on apps I use such as linkedin what they use in their apps for the same I found that linkedin used SSE for the chats and it just works very well I know they have put a lot of thought in selecting this as their primary system but it gave me a way then I learned about SSE and implimented it in my app. It has allowed me to have the following:
- Real-time server → client updates.
- Super easy scaling with existing HTTP infra.
- Less complexity to manage.
And to be honest that's all I need for my app I don't need like crazy good realtime updates its not Telegram or Discord. All I do is create a POST request for new message from clients and using simple redis queue and some pubsub magic it just works.
Simple. Effective. And no therapy sessions required.
Minimal Chat with SSE
Server (Django + Redis pub/sub):
import json
import redis
from django.http import StreamingHttpResponse
redis_client = redis.StrictRedis()
def stream(request, room_id):
def event_stream():
pubsub = redis_client.pubsub()
pubsub.subscribe(f"chat_{room_id}")
for message in pubsub.listen():
if message['type'] == 'message':
yield f"data: {message['data'].decode()}\n\n"
return StreamingHttpResponse(event_stream(), content_type="text/event-stream")
Client:
const eventSource = new EventSource(`/chat/stream/room123/`);
eventSource.onmessage = function(event) {
const message = JSON.parse(event.data);
console.log("New message:", message.text);
};
// Sending messages
document.querySelector("#send").onclick = () => {
fetch("/chat/send/", {
method: "POST",
body: JSON.stringify({ text: "Hello world" }),
});
};
Lessons Learned & Best Practices
- Start simple. Don’t dive into WebSockets unless you truly need bidirectional communication they just require lot more effort than they should. (If all you want is notifications, SSE is your friend.)
- Scale smartly. Use Redis pub/sub for message distribution. Throw in Nginx as a reverse proxy, and you’re good for a long time.
- Fallbacks matter. If SSE fails (say, old browsers), fall back to long-polling. Your users don’t care about protocols; they just want their message to show up.
- Measure before you optimize. Don’t assume you’ll have 10 million concurrent users tomorrow. Pick the tool that works now and is easy to evolve later.
Conclusion
To sum it up:
- SSE: Lightweight, simple, perfect for one-way updates.
- WebSockets: Powerful, full-duplex, perfect for heavy chat/gaming apps.
For my project, I chose SSE—because it was easy, scalable enough, and fit my use case without unnecessary complexity.
Real-time communication isn’t about flexing the fanciest tech—it’s about delivering the right experience without making your life miserable as a developer.
So, what about you? Did you pick SSE or WebSockets for your project? Let me know—I’d love to hear your war stories.
Top comments (0)