How to Build Real-Time Communication with Socket.IO and Node.js

- Published on

Real-time communication is a cornerstone of modern web apps. Features like live chat, collaborative editing, and instant notifications transform user experiences. This article explains sockets and shows how to enable real-time communication using Socket.IO and Node.js with a small TypeScript example.
What Is a Socket?
A socket is an endpoint for sending/receiving data over a network. It creates a bi‑directional channel between client and server. Unlike classic HTTP’s request–response, sockets keep a persistent connection so data can flow both ways without repeated requests.
Why sockets matter:
- Reduced latency: once connected, data is pushed instantly
- Scalability: efficient event‑driven communication
- Interactivity: live notifications, chats, dashboards, multiplayer games, IoT
Setup (TypeScript + Node.js)
mkdir real-time-app
cd real-time-app
npm init -y
# Runtime deps
npm install express socket.io
# Dev deps (TypeScript + types)
npm install -D typescript ts-node-dev @types/node @types/express
Initialize TypeScript:
npx tsc --init --rootDir src --outDir dist --esModuleInterop --resolveJsonModule --module commonjs --target es2020
Add scripts to package.json
:
{
"scripts": {
"dev": "ts-node-dev --respawn --transpile-only src/server.ts",
"build": "tsc",
"start": "node dist/server.js"
}
}
Server (src/server.ts)
import express from 'express'
import { createServer } from 'http'
import { Server } from 'socket.io'
import path from 'path'
const app = express()
const httpServer = createServer(app)
const io = new Server(httpServer, { cors: { origin: '*' } })
// Serve a simple client
app.use(express.static(path.join(__dirname, 'public')))
io.on('connection', (socket) => {
console.log('connected:', socket.id)
socket.on('chat:message', (text: string) => {
io.emit('chat:message', { id: socket.id, text, ts: Date.now() })
})
socket.on('disconnect', () => console.log('disconnected:', socket.id))
})
const PORT = process.env.PORT || 3000
httpServer.listen(PORT, () => console.log(`Listening on http://localhost:${PORT}`))
Client (public/index.html)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Socket.IO Chat</title>
<style>
body { font-family: system-ui, -apple-system, Segoe UI, Roboto, sans-serif; margin: 2rem; }
#messages { border: 1px solid #ddd; padding: 1rem; height: 240px; overflow-y: auto; }
form { margin-top: 1rem; display: flex; gap: 0.5rem; }
input { flex: 1; padding: 0.5rem; }
</style>
</head>
<body>
<h1>Real-time Chat</h1>
<div id="messages"></div>
<form id="form">
<input id="input" placeholder="Type a message..." />
<button type="submit">Send</button>
</form>
<script src="/socket.io/socket.io.js"></script>
<script>
const socket = io()
const messages = document.getElementById('messages')
const form = document.getElementById('form')
const input = document.getElementById('input')
function append(msg) {
const div = document.createElement('div')
div.textContent = msg
messages.appendChild(div)
messages.scrollTop = messages.scrollHeight
}
socket.on('connect', () => append(`Connected as ${socket.id}`))
socket.on('chat:message', (payload) => {
const when = new Date(payload.ts).toLocaleTimeString()
append(`[${when}] ${payload.id}: ${payload.text}`)
})
form.addEventListener('submit', (e) => {
e.preventDefault()
const text = input.value.trim()
if (!text) return
socket.emit('chat:message', text)
input.value = ''
input.focus()
})
</script>
</body>
</html>
Run It
npm run dev
Open two tabs at http://localhost:3000
and send messages: both tabs will update instantly.
Key Features of Socket.IO
- Event‑driven: custom events make communication intuitive
- Cross‑browser: provides fallbacks when WebSockets aren’t available
- Scalable: works with load balancers; supports adapters for clusters/Redis
Conclusion
Socket.IO with Node.js is a powerful combo for real‑time apps. You saw what sockets are, why they matter, and built a minimal chat to understand the flow. Extend this base to add auth, rooms, persistence, and horizontal scaling.