In the modern web, real-time communication is increasingly becoming a necessity. Whether it’s a live chat app, real-time analytics dashboard, multiplayer game, or stock ticker, WebSockets enable persistent two-way communication between client and server.
NestJS provides first-class support for WebSockets via the @nestjs/websockets
module. In this article, you’ll learn how to build real-time applications using WebSockets in NestJS, with practical examples and explanations.
Table of Contents
- What Are WebSockets?
- Why Use WebSockets in NestJS?
- Setting Up @nestjs/websockets
- Creating a WebSocket Gateway
- Handling WebSocket Events
- Broadcasting Messages
- Client Example with Socket.IO
- WebSocket Lifecycle Hooks
- Security Considerations
- Conclusion
What Are WebSockets?
WebSockets provide a full-duplex communication channel over a single TCP connection. Unlike HTTP, which is request-response based, WebSockets allow real-time interaction with low latency.
Use Cases:
- Real-time chat
- Live notifications
- Gaming servers
- Collaborative tools (e.g., Google Docs-style editing)
Why Use WebSockets in NestJS?
NestJS makes it incredibly easy to implement WebSockets using:
- Declarative decorators
- Modular gateway architecture
- Built-in support for
socket.io
andws
engines - Integration with DI and NestJS lifecycle
Setting Up @nestjs/websockets
Install the necessary dependencies:
bashCopyEditnpm install --save @nestjs/websockets @nestjs/platform-socket.io socket.io
If you prefer the ws
engine over socket.io
, you can replace socket.io
with ws
.
Creating a WebSocket Gateway
A Gateway in NestJS acts as a WebSocket server. Here’s how to create one.
Step 1: Create a Gateway
tsCopyEdit// chat.gateway.ts
import {
SubscribeMessage,
WebSocketGateway,
WebSocketServer,
MessageBody,
ConnectedSocket,
OnGatewayConnection,
OnGatewayDisconnect,
} from '@nestjs/websockets';
import { Server, Socket } from 'socket.io';
@WebSocketGateway({ cors: true }) // or pass custom namespace/port
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('message')
handleMessage(
@MessageBody() data: string,
@ConnectedSocket() client: Socket,
) {
console.log(`Message from ${client.id}: ${data}`);
this.server.emit('message', data); // broadcast to all clients
}
}
Step 2: Register in a Module
tsCopyEditimport { Module } from '@nestjs/common';
import { ChatGateway } from './chat.gateway';
@Module({
providers: [ChatGateway],
})
export class ChatModule {}
Handling WebSocket Events
NestJS maps WebSocket events using the @SubscribeMessage()
decorator. These are event-driven, similar to Express route handlers, but asynchronous and long-lived.
tsCopyEdit@SubscribeMessage('event_name')
handleCustomEvent(@MessageBody() data: any) {
// handle event here
}
Broadcasting Messages
You can emit events to all clients or selectively:
tsCopyEdit// To all clients
this.server.emit('event', payload);
// To one client
client.emit('event', payload);
// To all except sender
client.broadcast.emit('event', payload);
Client Example with Socket.IO
Here’s a minimal client using the Socket.IO client library.
htmlCopyEdit<script src="https://cdn.socket.io/4.5.4/socket.io.min.js"></script>
<script>
const socket = io('http://localhost:3000');
socket.on('connect', () => {
console.log('Connected to WebSocket server');
});
socket.emit('message', 'Hello from client!');
socket.on('message', (msg) => {
console.log('Received:', msg);
});
</script>
WebSocket Lifecycle Hooks
NestJS provides interfaces for connection lifecycle:
Hook | Interface |
---|---|
On client connect | OnGatewayConnection |
On client disconnect | OnGatewayDisconnect |
On init (optional) | OnGatewayInit |
Example:
tsCopyEdithandleConnection(client: Socket) {
console.log(`Client connected: ${client.id}`);
}
handleDisconnect(client: Socket) {
console.log(`Client disconnected: ${client.id}`);
}
Security Considerations
- Authentication: Use middleware to verify JWT on connection.
- Namespaces: Isolate gateways for different roles/features.
- Rate Limiting: Prevent flooding and abuse.
- CORS: Explicitly set CORS policies for WebSocket access.
Example: authenticating on connect
tsCopyEdit@WebSocketGateway()
export class SecureGateway implements OnGatewayConnection {
handleConnection(client: Socket) {
const token = client.handshake.headers.authorization?.replace('Bearer ', '');
if (!verifyToken(token)) {
client.disconnect();
}
}
}
Conclusion
With the @nestjs/websockets
module, NestJS offers a structured and powerful abstraction over WebSocket programming. You can build scalable, real-time applications that integrate seamlessly with the rest of your NestJS ecosystem.