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:

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:

HookInterface
On client connectOnGatewayConnection
On client disconnectOnGatewayDisconnect
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.