One data grid for JavaScript, React, Vue & Angular. Sorting, filtering, virtualization, pinning, and CSV export included. Early access $199 $349 → [Get it now]

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.


Speed up your responsive apps and websites with fully-featured, ready-to-use open-source admin panel templates—free to use and built for efficiency.


About the Author

Subscribe to our newsletter
Get early information about new products, product updates and blog posts.