How to implement real-time notifications in Node.js
Real-time notifications keep users informed of important events without requiring page refreshes or polling, creating responsive and engaging applications. As the creator of CoreUI with over 12 years of Node.js experience since 2014, I’ve implemented notification systems for numerous enterprise dashboards. A real-time notification system uses WebSockets to maintain persistent connections and push notifications instantly when events occur. This approach provides immediate user feedback for actions like new messages, status updates, or system alerts.
Create a notification service using WebSockets to push real-time updates to authenticated users.
const WebSocket = require('ws')
const http = require('http')
class NotificationService {
constructor(server) {
this.wss = new WebSocket.Server({ server })
this.userConnections = new Map() // userId -> Set of WebSocket connections
this.wss.on('connection', (ws, req) => {
this.handleConnection(ws, req)
})
}
handleConnection(ws, req) {
let userId = null
ws.on('message', (data) => {
try {
const message = JSON.parse(data)
// Authenticate user
if (message.type === 'auth') {
userId = message.userId // In production, validate token
this.registerUser(userId, ws)
ws.send(JSON.stringify({
type: 'auth_success',
message: 'Connected to notification service'
}))
}
} catch (error) {
console.error('Error handling message:', error)
}
})
ws.on('close', () => {
if (userId) {
this.unregisterUser(userId, ws)
}
})
}
registerUser(userId, ws) {
if (!this.userConnections.has(userId)) {
this.userConnections.set(userId, new Set())
}
this.userConnections.get(userId).add(ws)
console.log(`User ${userId} connected. Total connections: ${this.userConnections.get(userId).size}`)
}
unregisterUser(userId, ws) {
const connections = this.userConnections.get(userId)
if (connections) {
connections.delete(ws)
if (connections.size === 0) {
this.userConnections.delete(userId)
}
}
}
sendToUser(userId, notification) {
const connections = this.userConnections.get(userId)
if (!connections) return
const message = JSON.stringify({
type: 'notification',
...notification,
timestamp: new Date().toISOString()
})
connections.forEach(ws => {
if (ws.readyState === WebSocket.OPEN) {
ws.send(message)
}
})
}
sendToMultipleUsers(userIds, notification) {
userIds.forEach(userId => {
this.sendToUser(userId, notification)
})
}
broadcast(notification) {
const message = JSON.stringify({
type: 'notification',
...notification,
timestamp: new Date().toISOString()
})
this.userConnections.forEach((connections) => {
connections.forEach(ws => {
if (ws.readyState === WebSocket.OPEN) {
ws.send(message)
}
})
})
}
}
// Usage example
const server = http.createServer()
const notificationService = new NotificationService(server)
// Simulate sending notifications
setInterval(() => {
notificationService.sendToUser('user123', {
title: 'New Message',
body: 'You have received a new message',
priority: 'high'
})
}, 10000)
// Broadcast to all users
notificationService.broadcast({
title: 'System Maintenance',
body: 'Scheduled maintenance in 1 hour',
priority: 'medium'
})
server.listen(3000, () => {
console.log('Notification service running on port 3000')
})
Client-side usage:
const ws = new WebSocket('ws://localhost:3000')
ws.onopen = () => {
// Authenticate
ws.send(JSON.stringify({
type: 'auth',
userId: 'user123',
token: 'your-auth-token'
}))
}
ws.onmessage = (event) => {
const data = JSON.parse(event.data)
if (data.type === 'notification') {
showNotification(data.title, data.body, data.priority)
}
}
function showNotification(title, body, priority) {
// Display notification in UI
console.log(`[${priority}] ${title}: ${body}`)
}
Best Practice Note
Store user-to-connection mappings to efficiently route notifications to specific users. Support multiple connections per user for users with multiple browser tabs. Implement exponential backoff for automatic reconnection on disconnect. Queue notifications if the user is offline and deliver when they reconnect. Add notification persistence with a database for notification history. This is how we build notification systems for CoreUI dashboards—using WebSockets for instant delivery with proper user authentication, connection management, and graceful error handling.



