Difficulty: Advanced
How do you implement real-time communication in Node.js? Explain WebSockets and Socket.IO.
WebSockets provide full-duplex, persistent connections between client and server, enabling real-time bidirectional communication. Unlike HTTP (request-response), WebSocket connections stay open, allowing the server to push data to clients instantly.
Socket.IO is the most popular WebSocket library for Node.js. It builds on top of WebSockets with fallback to long-polling, automatic reconnection, rooms/namespaces for grouping connections, and built-in event handling.
Common real-time use cases include: chat applications, live notifications, collaborative editing, real-time dashboards, gaming, and live location tracking. WebSockets are ideal when you need instant updates without the overhead of repeated HTTP polling.
Socket.IO rooms group connected clients so you can broadcast messages to specific subsets (e.g., all users in a chat room, all admins). Namespaces provide separate communication channels within a single connection (e.g., /chat and /notifications).
const express = require('express');
const { createServer } = require('http');
const { Server } = require('socket.io');
const app = express();
const httpServer = createServer(app);
const io = new Server(httpServer, {
cors: {
origin: 'http://localhost:5173',
methods: ['GET', 'POST'],
},
});
// Connection event
io.on('connection', (socket) => {
console.log('User connected:', socket.id);
// Listen for events from client
socket.on('chat:message', (data) => {
console.log('Message:', data);
// Broadcast to all clients except sender
socket.broadcast.emit('chat:message', {
user: data.user,
text: data.text,
timestamp: new Date(),
});
});
// Typing indicator
socket.on('chat:typing', (user) => {
socket.broadcast.emit('chat:typing', user);
});
socket.on('disconnect', (reason) => {
console.log('User disconnected:', socket.id, reason);
});
});
httpServer.listen(3000, () => {
console.log('Server with WebSocket on port 3000');
});
Socket.IO wraps the HTTP server. Events are custom-named. broadcast.emit sends to all except the sender. disconnect fires on close.
const io = new Server(httpServer);
// Rooms: group clients for targeted broadcasting
io.on('connection', (socket) => {
// Join a room
socket.on('room:join', (roomId) => {
socket.join(roomId);
socket.to(roomId).emit('room:userJoined', {
userId: socket.userId,
roomId,
});
});
// Send message to specific room
socket.on('room:message', ({ roomId, text }) => {
io.to(roomId).emit('room:message', {
user: socket.userId,
text,
roomId,
timestamp: Date.now(),
});
});
// Leave room
socket.on('room:leave', (roomId) => {
socket.leave(roomId);
});
});
// Namespaces: separate communication channels
const chatNs = io.of('/chat');
const notifNs = io.of('/notifications');
chatNs.on('connection', (socket) => {
console.log('Chat connected:', socket.id);
});
notifNs.on('connection', (socket) => {
console.log('Notifications connected:', socket.id);
// Send notification to this user only
socket.emit('notification', { text: 'Welcome back!' });
});
Rooms let you broadcast to subsets of clients. Namespaces are separate connection scopes on the same underlying connection.
const jwt = require('jsonwebtoken');
// Socket.IO middleware for auth
io.use((socket, next) => {
const token = socket.handshake.auth.token;
if (!token) {
return next(new Error('Authentication required'));
}
try {
const decoded = jwt.verify(token, process.env.JWT_SECRET);
socket.userId = decoded.id;
socket.userRole = decoded.role;
next();
} catch (err) {
next(new Error('Invalid token'));
}
});
// Now all connections are authenticated
io.on('connection', (socket) => {
console.log('Authenticated user:', socket.userId);
// Join personal room for targeted notifications
socket.join(`user:${socket.userId}`);
});
// Send notification to specific user from anywhere
function notifyUser(userId, event, data) {
io.to(`user:${userId}`).emit(event, data);
}
// Client-side connection
// const socket = io('http://localhost:3000', {
// auth: { token: localStorage.getItem('accessToken') }
// });
Socket.IO middleware runs on connection. Attach user data to the socket object. Use personal rooms (user:ID) for targeted notifications.
WebSocket, Socket.IO, Real-Time, Events, Rooms