Real-time chat applications are a perfect use case for WebSockets. In this module, we’ll build a basic chat app using NestJS WebSocket Gateways, Socket.IO rooms, and custom events. You’ll learn how to structure a real-time communication system with NestJS that supports multiple users and chat rooms.
Table of Contents
- Overview of Real-Time Chat Features
- Setting Up the WebSocket Gateway
- Creating Chat Rooms Using Socket.IO
- Managing Users and Broadcasting Events
- Frontend Socket.IO Client
- Handling Room Events and Messages
- Bonus: Persisting Messages (Optional)
- Conclusion
Overview of Real-Time Chat Features
In our chat app, users can:
- Connect via WebSocket
- Join specific rooms (like channels)
- Send messages to others in the same room
- Receive messages in real-time
- Optionally persist messages in a database
We’ll use:
@nestjs/websockets
for gateway setupsocket.io
for client-server real-time communication- Simple in-memory logic for rooms and broadcasting
Setting Up the WebSocket Gateway
Install the required packages if you haven’t already:
bashCopyEditnpm install @nestjs/websockets @nestjs/platform-socket.io socket.io
Create a WebSocket Gateway:
tsCopyEdit// chat.gateway.ts
import {
WebSocketGateway,
WebSocketServer,
SubscribeMessage,
MessageBody,
ConnectedSocket,
} from '@nestjs/websockets';
import { Server, Socket } from 'socket.io';
@WebSocketGateway({ cors: true })
export class ChatGateway {
@WebSocketServer()
server: Server;
@SubscribeMessage('joinRoom')
handleJoinRoom(
@MessageBody() room: string,
@ConnectedSocket() client: Socket,
) {
client.join(room);
client.emit('joinedRoom', `Joined room: ${room}`);
}
@SubscribeMessage('sendMessage')
handleMessage(
@MessageBody() payload: { room: string; message: string },
@ConnectedSocket() client: Socket,
) {
const { room, message } = payload;
this.server.to(room).emit('receiveMessage', {
user: client.id,
message,
});
}
}
Creating Chat Rooms Using Socket.IO
With Socket.IO, creating rooms is simple. You use client.join(roomName)
to add a client to a room. Rooms can be dynamic and identified by chat group names, user IDs, or custom IDs.
tsCopyEditclient.join('dev-room'); // Adds client to the 'dev-room'
Messages can then be scoped to a room:
tsCopyEditthis.server.to('dev-room').emit('receiveMessage', payload);
Managing Users and Broadcasting Events
To enhance functionality, you can track connected users and rooms using a simple map or a database.
Example:
tsCopyEditconst activeUsers: Record<string, string> = {}; // clientId -> username
@SubscribeMessage('register')
handleRegister(
@MessageBody() username: string,
@ConnectedSocket() client: Socket,
) {
activeUsers[client.id] = username;
client.emit('registered', `Welcome, ${username}`);
}
When a user sends a message:
tsCopyEditthis.server.to(room).emit('receiveMessage', {
user: activeUsers[client.id] || client.id,
message,
});
Frontend Socket.IO Client
htmlCopyEdit<script src="https://cdn.socket.io/4.5.4/socket.io.min.js"></script>
<script>
const socket = io('http://localhost:3000');
socket.emit('joinRoom', 'room1');
socket.on('joinedRoom', (msg) => {
console.log(msg);
});
socket.emit('sendMessage', {
room: 'room1',
message: 'Hello Room!',
});
socket.on('receiveMessage', (msg) => {
console.log(`[${msg.user}]: ${msg.message}`);
});
</script>
Handling Room Events and Messages
You can extend your gateway to handle:
- User typing indicators
- Message read receipts
- User disconnection announcements
- Notifications for new users
Example: Notify room on user join
tsCopyEdithandleJoinRoom(room: string, client: Socket) {
client.join(room);
this.server.to(room).emit('userJoined', {
user: client.id,
room,
});
}
Bonus: Persisting Messages (Optional)
For production apps, persist messages using a database:
- Create a Message entity/model
- Use a MessageService to save chat data
- Call the service in
handleMessage
tsCopyEditawait this.messageService.save({
room,
userId: client.id,
message,
timestamp: new Date(),
});
Conclusion
You’ve now built a simple but powerful chat app using NestJS Gateways and Socket.IO. You’ve learned how to:
- Create and manage chat rooms
- Handle real-time message delivery
- Build a frontend that interacts with the backend
- Optionally persist chat messages