How to build a chat app with WebSockets in Node.js
Real-time chat applications require bidirectional communication where the server can push messages to clients instantly without polling.
As the creator of CoreUI, I’ve built numerous real-time applications with WebSockets.
WebSockets provide full-duplex communication channels over a single TCP connection, perfect for chat, notifications, and live updates.
The native ws library offers a lightweight WebSocket implementation for Node.js without the overhead of frameworks.
Use the ws library to create a WebSocket server that broadcasts messages to all connected clients.
npm install ws
Create WebSocket chat server:
const WebSocket = require('ws')
const http = require('http')
const server = http.createServer()
const wss = new WebSocket.Server({ server })
const clients = new Set()
wss.on('connection', (ws) => {
console.log('New client connected')
clients.add(ws)
// Send welcome message
ws.send(JSON.stringify({
type: 'system',
message: 'Welcome to the chat!',
timestamp: new Date().toISOString()
}))
// Broadcast user joined
broadcast({
type: 'system',
message: 'A user joined the chat',
timestamp: new Date().toISOString()
}, ws)
// Handle incoming messages
ws.on('message', (data) => {
try {
const message = JSON.parse(data)
// Broadcast to all clients
broadcast({
type: 'message',
user: message.user || 'Anonymous',
text: message.text,
timestamp: new Date().toISOString()
})
} catch (error) {
console.error('Error parsing message:', error)
}
})
// Handle disconnect
ws.on('close', () => {
console.log('Client disconnected')
clients.delete(ws)
broadcast({
type: 'system',
message: 'A user left the chat',
timestamp: new Date().toISOString()
})
})
ws.on('error', (error) => {
console.error('WebSocket error:', error)
clients.delete(ws)
})
})
function broadcast(data, exclude = null) {
const message = JSON.stringify(data)
clients.forEach(client => {
if (client !== exclude && client.readyState === WebSocket.OPEN) {
client.send(message)
}
})
}
server.listen(3000, () => {
console.log('Chat server running on port 3000')
})
Client-side JavaScript:
const ws = new WebSocket('ws://localhost:3000')
ws.onopen = () => {
console.log('Connected to chat server')
}
ws.onmessage = (event) => {
const data = JSON.parse(event.data)
displayMessage(data)
}
function sendMessage(text) {
ws.send(JSON.stringify({
user: 'John',
text: text
}))
}
function displayMessage(data) {
console.log(`[${data.timestamp}] ${data.user}: ${data.text}`)
}
Best Practice Note
Always validate and sanitize incoming messages to prevent XSS attacks. Track connected clients in a Set for efficient broadcasts. Check readyState === WebSocket.OPEN before sending to avoid errors. Implement heartbeat/ping-pong to detect dead connections. For production, add user authentication, message persistence, and rate limiting. Consider Socket.IO for broader browser support and automatic fallbacks. This is how we build real-time features in CoreUI backends—using native WebSockets for performance with proper error handling and connection management.



