WebSockets (ws & Socket.IO)
WebSockets keep a single connection open so the server and client can push messages to each other at any time, making them the foundation for real-time features like chat, live dashboards, and multiplayer games.
Learn WebSockets (ws & Socket.IO) in our free Node.js course — a beginner-friendly interactive lesson with worked examples, a practice exercise and a quick…
Part of the free Node.js course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
In this lesson you'll see how WebSockets differ from request/response HTTP, write a server with the lean ws library, use Socket.IO's events, rooms, and broadcasting, and learn when a WebSocket is the right tool versus plain HTTP.
What You'll Learn in This Lesson
1️⃣ HTTP vs WebSocket: the emit/on Model
With HTTP, the client asks and the server answers, then the exchange is over. With a WebSocket, the connection stays open and both sides communicate by emitting named events and listening for them — exactly the pattern of Node's EventEmitter , which is why we use it to model the idea.
In the snippet below, socket.on('name', handler) subscribes to an event and socket.emit('name', data) fires one. The server reacts to a client message and pushes one back — the two-way flow that defines WebSockets.
2️⃣ A Real Server with the ws Library
The ws library is the lean, standards-based choice. You create a WebSocketServer , handle the 'connection' event for each client, then listen for that client's 'message' and call socket.send(...) to push data back. The browser's built-in WebSocket object talks to it directly — no client library needed.
3️⃣ Socket.IO: Events, Rooms & Broadcasting
Socket.IO layers convenience on top of WebSockets: named events, automatic reconnection, and rooms . A room is a named group of connections. A socket join() s a room, and you broadcast with io.to(room).emit(...) (everyone in it) or socket.to(room).emit(...) (everyone except the sender).
Here's the rooms-and-broadcast logic as a runnable plain-Node model, so you can see exactly who receives a broadcast and who doesn't:
Your turn. The ping/pong below works once you fill in the single blank marked ___ . Follow the 👉 hint, then run it.
Mini-Challenge: A Two-Client Chat
No blanks — just a brief and an outline. Model a two-person chat over one shared event bus, where each client sees the other's messages but not its own. Write it, run it, and compare with the example output.
Common Errors (and the fix)
- ❌ Printing <Buffer ...> instead of text — ws delivers messages as Buffers. ✅ Call data.toString() to read them as strings.
- ❌ Browser native WebSocket can't connect to a Socket.IO server — Socket.IO uses its own protocol. ✅ Use the socket.io-client on the front end, or use ws on the server for the native API.
- ❌ Broadcasts go to everyone including the sender — io.to(room) includes the sender. ✅ Use socket.to(room) to exclude them.
- ❌ Real-time breaks across multiple server instances — each instance only knows its own connections. ✅ Add the Socket.IO Redis adapter (or sticky sessions) so rooms span all instances.
- ❌ Mixed ws:// on an https page — browsers block insecure WebSockets on secure pages. ✅ Use wss:// over TLS in production.
Pro Tips
- 💡 Pick the smallest tool that fits: native ws for a lean custom protocol, Socket.IO when you want rooms, reconnection, and fallbacks for free.
- 💡 For one-way pushes, consider Server-Sent Events: they're simpler than WebSockets when only the server needs to push.
- 💡 Scale with the Redis adapter: it lets rooms and broadcasts work across many Node instances behind a load balancer.
📋 Quick Reference — WebSocket Messaging
Task
Syntax
Listen for an event
socket.on('name', fn)
Send an event
socket.emit('name', data)
ws: send to a client
socket.send(text)
Join a room
socket.join(room)
To everyone in a room
io.to(room).emit(...)
To room, not sender
socket.to(room).emit(...)
Secure connection
wss://host
Frequently Asked Questions
🎉 Lesson Complete!
- ✅ WebSockets keep one connection open for two-way, real-time messaging
- ✅ The emit / on event model mirrors Node's EventEmitter
- ✅ The ws library gives a lean, standards-based server
- ✅ Socket.IO adds rooms, broadcasting, reconnection, and fallbacks
- ✅ io.to(room) includes the sender; socket.to(room) excludes them
- ✅ Use WebSockets for frequent two-way updates; HTTP or SSE for simpler cases
- ✅ Next lesson: GraphQL APIs — query exactly the data you need
Practice quiz
What is the key difference between HTTP and WebSockets?
- WebSockets keep one connection open so either side can push anytime
- HTTP is always faster
- WebSockets cannot send text
- HTTP keeps a persistent socket
Answer: WebSockets keep one connection open so either side can push anytime. A WebSocket is a persistent full-duplex channel; HTTP is request/response.
Which Node built-in models the emit/on event style used by Socket.IO?
- fs
- EventEmitter
- Buffer
- cluster
Answer: EventEmitter. EventEmitter's on()/emit() pattern mirrors how WebSocket messaging works.
With the ws library, in what form do incoming messages arrive?
- A parsed JSON object
- A number
- A Buffer (call .toString() for text)
- An HTML string
Answer: A Buffer (call .toString() for text). ws delivers messages as Buffers; use data.toString() to read text.
How does a socket join a named group in Socket.IO?
- socket.group(name)
- io.add(name)
- socket.room = name
- socket.join(room)
Answer: socket.join(room). socket.join('room') adds the connection to that room.
Which call broadcasts to everyone in a room EXCEPT the sender?
- socket.to(room).emit(...)
- io.to(room).emit(...)
- io.emit(...)
- socket.send(...)
Answer: socket.to(room).emit(...). socket.to(room) excludes the sender; io.to(room) includes everyone.
Why can't a browser's native WebSocket connect to a Socket.IO server?
- The port is blocked
- Socket.IO uses its own protocol, needing socket.io-client
- Native WebSocket is deprecated
- Socket.IO only accepts HTTP
Answer: Socket.IO uses its own protocol, needing socket.io-client. Socket.IO has its own protocol; the browser must use socket.io-client.
When is a simpler alternative than WebSockets a better fit?
- For multiplayer games
- For high-frequency two-way updates
- For occasional one-way server pushes (Server-Sent Events)
- Never, WebSockets always win
Answer: For occasional one-way server pushes (Server-Sent Events). SSE is simpler when only the server needs to push occasionally.
Which library is the lean, standards-based WebSocket choice?
- socket.io
- express
- axios
- ws
Answer: ws. ws speaks the raw WebSocket protocol the browser's WebSocket understands.
On an HTTPS page, which WebSocket scheme must you use?
- wss://
- ws://
- http://
- ftp://
Answer: wss://. Browsers block insecure ws:// on secure pages; use wss:// over TLS.
What problem appears when running Socket.IO across multiple instances?
- Messages are encrypted twice
- Each instance only knows its own connections, so rooms break
- The port changes randomly
- Clients can't reconnect at all
Answer: Each instance only knows its own connections, so rooms break. You need the Redis adapter or sticky sessions so rooms span all instances.
Continue this course
- Previous: Scaling with the cluster Module
- Next: GraphQL APIs