WebSockets in NestJS with @nestjs/websockets

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

  1. What Are WebSockets?
  2. Why Use WebSockets in NestJS?
  3. Setting Up @nestjs/websockets
  4. Creating a WebSocket Gateway
  5. Handling WebSocket Events
  6. Broadcasting Messages
  7. Client Example with Socket.IO
  8. WebSocket Lifecycle Hooks
  9. Security Considerations
  10. 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 and ws engines
  • Integration with DI and NestJS lifecycle

Setting Up @nestjs/websockets

Install the necessary dependencies:

npm 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

// 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

import { 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.

@SubscribeMessage('event_name')
handleCustomEvent(@MessageBody() data: any) {
// handle event here
}

Broadcasting Messages

You can emit events to all clients or selectively:

// 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.

<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:

HookInterface
On client connectOnGatewayConnection
On client disconnectOnGatewayDisconnect
On init (optional)OnGatewayInit

Example:

handleConnection(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

@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.