Build a Real-Time Chat App with NestJS and WebSockets
WEB DEVELOPMENT

Build a Real-Time Chat App with NestJS and WebSockets

JJ Chan
JJ ChanThu, Apr 24, 2025
Share this:

A while back, I was working on a small app for a friend who was running virtual events — think webinars, coaching calls, the works.

She wanted a chat system baked into the app. “Can we make it real-time, like messages pop up without refreshing?”

And just like that, we were off to the races with WebSockets.

If you’ve ever wanted to add real-time communication to your app — think chat, live notifications, collaborative tools — this guide is for you.

We’re going to use NestJS with WebSocket Gateway support to set it up cleanly. No spaghetti code, no bloated frameworks — just clean, modular Nest magic.

Below is a preview of the real-time NestJS chat application we'll build step-by-step in this tutorial.

Built with NestJS, Socket.IO, and React — experience live messaging in action.

What Are WebSockets?

Normally, HTTP is like yelling across a canyon — you shout a request, then wait for a response.

WebSockets, on the other hand, are more like a phone call. Once it’s connected, you can send messages both ways, anytime. Perfect for anything that feels “live.”

And in NestJS, it’s ridiculously easy to use thanks to the @WebSocketGateway() decorator.

Set Up a New NestJS Project

If you haven’t already, let’s spin up a fresh NestJS app:

npm i -g @nestjs/cli nest new nest-ws-demo

Pick your package manager and wait for the magic to finish.

Install WebSocket Dependencies

Nest comes with WebSocket support out of the box, but we’ll explicitly install @nestjs/websockets and socket.io to keep things clean.

npm install @nestjs/websockets @nestjs/platform-socket.io socket.io

Boom. Now we’re WebSocket-ready.

Create a Gateway

This is where the fun begins. Let’s make a chat gateway:

nest generate gateway chat

Now open up chat.gateway.ts. You’ll see a basic class. Let’s flesh it out:

import { WebSocketGateway, SubscribeMessage, MessageBody, OnGatewayConnection, OnGatewayDisconnect, WebSocketServer, } from '@nestjs/websockets'; import { Server, Socket } from 'socket.io'; @WebSocketGateway({ cors: { origin: '*', }, }) export class ChatGateway implements OnGatewayConnection, OnGatewayDisconnect { @WebSocketServer() server: Server; handleConnection(client: Socket) { console.log(`Client connected: ${client.id}`); } handleDisconnect(client: Socket) { console.log(`Client disconnected: ${client.id}`); } @SubscribeMessage('chat') handleChatMessage(@MessageBody() message: string): void { console.log('Message received:', message); this.server.emit('chat', message); // Broadcast to everyone } }

Let’s break it down:

@WebSocketGateway() sets up the server.

handleConnection + handleDisconnect keep tabs on who joins/leaves.

@SubscribeMessage('chat') listens for chat events and rebroadcasts them.

Easy.

Try It Out with a Frontend

Let’s test this in the browser. Make an index.html like this:

<!DOCTYPE html> <html> <body> <h1>Simple Chat</h1> <input id="msg" placeholder="Type a message" /> <button onclick="send()">Send</button> <ul id="messages"></ul> <script src="https://cdn.socket.io/4.5.4/socket.io.min.js"></script> <script> const socket = io('http://localhost:3000'); socket.on('chat', (msg) => { const li = document.createElement('li'); li.textContent = msg; document.getElementById('messages').appendChild(li); }); function send() { const input = document.getElementById('msg'); const message = input.value; socket.emit('chat', message); input.value = ''; } </script> </body> </html>

Now run your NestJS app:

npm run start:dev

Open index.html in your browser, type a message, and boom — real-time chat.

Open it in multiple tabs to see the magic live.

Bonus: Namespaces & Rooms

Want to group users by chat room? Nest makes it super easy to work with rooms:

@SubscribeMessage('joinRoom') handleJoinRoom(@MessageBody() data: { room: string }, @ConnectedSocket() client: Socket) { client.join(data.room); client.emit('joinedRoom', data.room); } @SubscribeMessage('roomMessage') handleRoomMessage(@MessageBody() data: { room: string; message: string }) { this.server.to(data.room).emit('roomMessage', data.message); }

Now users can join specific rooms and send messages within them — super handy for things like private chats or group sessions.

And there you go — a real-time chat system using WebSockets in NestJS with barely any friction.

To recap:

  • We set up a basic NestJS project

  • Created a WebSocket gateway

  • Built a frontend to test it

  • Added support for rooms (optional but awesome)

Nest makes this crazy smooth. You don’t have to dig into raw socket handling or write a ton of boilerplate. Just build what matters.

If you're adding this to a bigger app — say, a support system, real-time orders dashboard, or multiplayer game — you’ve now got the foundation.

Let me know if you want to go deeper into authentication, scaling with Redis, or deploying this in production. Happy to break it down in a follow-up.

You’ve got this. 🚀

Want to see how I can help? Let’s build something together →

Related Articles

Join our Newsletter

Stay updated with the latest trends in web design and development. Our newsletter delivers expert insights, tips, and industry news to help your business thrive online.