How to use Socket.IO in Node.js
Real-time bidirectional communication requires WebSockets, but handling browser compatibility and reconnection logic manually is complex. With over 12 years of Node.js development experience since 2014 and as the creator of CoreUI, I’ve built numerous real-time features with Socket.IO. Socket.IO is a library that provides WebSocket functionality with automatic fallbacks, reconnection, and room-based broadcasting. This approach simplifies real-time communication compared to native WebSockets while adding powerful features like namespaces and middleware.
Use Socket.IO to create real-time servers with WebSocket connections and automatic fallback support.
npm install socket.io
Create Socket.IO server:
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, {
cors: {
origin: 'http://localhost:3000',
methods: ['GET', 'POST']
}
})
// Handle connections
io.on('connection', (socket) => {
console.log('User connected:', socket.id)
// Listen for custom events
socket.on('message', (data) => {
console.log('Message received:', data)
// Emit to all clients
io.emit('message', {
id: socket.id,
text: data.text,
timestamp: Date.now()
})
})
// Join a room
socket.on('join-room', (roomName) => {
socket.join(roomName)
console.log(`${socket.id} joined room: ${roomName}`)
// Emit to room
io.to(roomName).emit('user-joined', {
userId: socket.id,
room: roomName
})
})
// Emit to specific room
socket.on('room-message', (data) => {
io.to(data.room).emit('message', {
id: socket.id,
text: data.text,
room: data.room
})
})
// Private message
socket.on('private-message', (data) => {
socket.to(data.recipientId).emit('private-message', {
from: socket.id,
text: data.text
})
})
// Broadcast (to all except sender)
socket.on('broadcast', (data) => {
socket.broadcast.emit('broadcast', data)
})
// Handle disconnect
socket.on('disconnect', () => {
console.log('User disconnected:', socket.id)
})
})
server.listen(3000, () => {
console.log('Socket.IO server running on port 3000')
})
Client-side usage:
const socket = io('http://localhost:3000')
// Connect event
socket.on('connect', () => {
console.log('Connected:', socket.id)
})
// Listen for messages
socket.on('message', (data) => {
console.log('Message:', data)
displayMessage(data)
})
// Send message
function sendMessage(text) {
socket.emit('message', { text })
}
// Join room
socket.emit('join-room', 'general')
// Send room message
socket.emit('room-message', {
room: 'general',
text: 'Hello room'
})
// Handle disconnect
socket.on('disconnect', () => {
console.log('Disconnected')
})
With namespaces:
// Server
const adminNamespace = io.of('/admin')
adminNamespace.on('connection', (socket) => {
console.log('Admin connected')
socket.on('admin-action', (data) => {
adminNamespace.emit('admin-update', data)
})
})
// Client
const adminSocket = io('http://localhost:3000/admin')
Best Practice Note
Socket.IO automatically handles reconnection with exponential backoff. Use rooms for efficient broadcasting to specific user groups. Namespaces provide complete separation of concerns for different parts of your application. Add middleware for authentication before allowing connections. Use acknowledgments for confirmation that messages were received. Socket.IO falls back to long-polling if WebSockets aren’t available. This is how we build real-time features in CoreUI dashboards—using Socket.IO for reliable bidirectional communication with automatic fallbacks and efficient room-based broadcasting.



