Blog
Building Real-Time Features with Node.js and Socket.IO
Build interactive, live experiences without wrestling with low-level networking details.
Before the internet, communication looked like this: you’d write a letter, drop it in the mailbox, and wait days for a reply. Early websites weren’t that different. You sent a request, waited for the server, and refreshed to see what changed. The web used to be that simple. But today, users expect instant updates. Be it chat messages that appear in real-time, live notifications, dashboards that update without hitting refresh.
Then came AJAX in the early 2000s, and suddenly pages could fetch bits of data without reloading. That opened the door for features like live search suggestions and background updates.
But as users demanded more live chat, multiplayer games, collaborative tools, developers started to hack together “real-time” with long polling and other tricks. These worked, but they were clunky, unreliable, and hard to scale.
Enter WebSockets: a protocol that let browsers and servers keep a persistent two-way connection. Real-time communication was finally possible. And on top of WebSockets, libraries like Socket.IO emerged to smooth over the rough edges, handling fallbacks, reconnections, and cross-browser quirks so you could just focus on building.

What is Socket.IO?
Socket.IO is a JavaScript library that enables real-time, bidirectional communication between clients (usually browsers) and servers. It’s built on top of WebSockets but adds important features like:
- Automatic reconnection
- Event-based communication (you can define custom events)
- Support for rooms and namespaces
- Fallbacks when WebSockets aren’t available
With Node.js on the backend and Socket.IO handling connections, you can build highly interactive applications with just a few lines of code.
Setting Up the Project
First, let’s scaffold a Node.js app with Express and Socket.IO.

server.js:
const express = require('express');
const http = require('http');
const { Server } = require('socket.io');
const app = express();
const server = http.createServer(app);
const io = new Server(server);
app.get('/', (req, res) => {
res.sendFile(__dirname + '/index.html');
});
io.on('connection', (socket) => {
console.log('A user connected');
socket.on('disconnect', () => {
console.log('A user disconnected');
});
});
server.listen(3000, () => {
console.log('http://localhost:3000');
});
index.html:
<ul id="messages"></ul>
<form id="form">
<input id="input" autocomplete="off" /><button>Send</button>
</form>
<script src="/socket.io/socket.io.js"></script>
<script>
const socket = io();
const form = document.getElementById('form');
const input = document.getElementById('input');
const messages = document.getElementById('messages');
form.addEventListener('submit', (e) => {
e.preventDefault();
if (input.value) {
socket.emit('chat message', input.value);
input.value = '';
}
});
socket.on('chat message', (msg) => {
const li = document.createElement('li');
li.textContent = msg;
messages.appendChild(li);
});
</script>
Broadcast Messages
Alright, let’s make every message visible to all connected clients
Now update the server, replace the original io.on('connection', …) block (where you only logged A user connected) with this new one that listens for chat messages and broadcasts them to everyone:
io.on('connection', (socket) => {
console.log('A user connected');
socket.on('chat message', (msg) => {
// Broadcast to ALL connected clients
io.emit('chat message', msg);
});
socket.on('disconnect', () => {
console.log('A user disconnected');
});
});
Here's a demo of what we just built:
Run the server with node server.js, open two browser tabs, and type. Each message appears instantly in both tabs. That’s broadcasting in action.
Moving Into Rooms
Broadcasting to everyone is fun, but real apps use rooms. Taking this up a notch, let's create a separate channels where only some users see messages. Think #general, #random, or private groups.
How It Works Behind the Scenes
- When a new socket (user) connects, they’re connected to the server, but not in any room yet.
- If they emit a join-room event with a room name e.g., general, the server adds their socket to that room.
- Now, when they or anyone else sends a room-message to general, the server only delivers that message to sockets inside general.
- Other users in different rooms won’t see it — the communication is isolated.
Click here for source code.
Although we just built a chat with rooms, Socket.IO is much more versatile. Any situation where you need instant, event-driven updates is a good fit. Some examples:
We started with a simple broadcast system, then introduced rooms to create multiple channels. This is the foundation of nearly every interactive app you use today.
What makes Socket.IO powerful is not just real-time messaging, but the flexibility: you can group users, separate features, and scale to handle thousands of concurrent connections.