← Back to list

WebSockets in NestJS (Part 2)

In Part 1, we covered how WebSockets work and how to implement basic communication using NestJS gateways. That foundation is enough for…

Silversky Technology · 2026-05-27 05:24 · 202 claps · 4.2 min read
#nestjs #websocket #backend-development #microservices
Open on Medium ↗
Wiki topics: 🌐 · Web Development 🔒 · Cybersecurity

WebSockets in NestJS (Part 2)

In Part 1, we covered how WebSockets work and how to implement basic communication using NestJS gateways. That foundation is enough for simple real-time features, but real applications require more structure.

In production systems, we need to handle multiple users efficiently, secure connections, validate incoming data, and ensure the system remains stable under load. This part focuses on those practical patterns.

Key Points

  • Real-time apps require structured communication
  • Users must be grouped efficiently
  • Authentication is required for security
  • Data validation prevents bad input
  • Error handling ensures system stability

Room Management (Group Communication)

Rooms allow you to group multiple users and send messages only to relevant clients instead of broadcasting to everyone.

  • A room is a logical group of sockets
  • A user can join multiple rooms
  • Messages can be targeted to specific rooms
  • Useful for chat, orders, live sessions

Join Room

@SubscribeMessage('joinRoom')
handleJoinRoom(
  @MessageBody() data: { roomId: string },
  @ConnectedSocket() client: Socket,
) {
  client.join(data.roomId);
  this.server.to(data.roomId).emit('userJoined', {
    userId: client.id,
  });
}

Send Message to Room

@SubscribeMessage('roomMessage')
  handleRoomMessage(
  @MessageBody() data: { roomId: string; message: string },
  @ConnectedSocket() client: Socket,
) {
  this.server.to(data.roomId).emit('receiveMessage', {
    userId: client.id,
    message: data.message,
  });
}

How It Works

When a client joins a room, the socket is internally mapped to that group. After joining, any message sent using server.to(roomId) will only reach clients in that room. This avoids unnecessary broadcasting and keeps communication efficient.

Authentication with JWT

WebSocket connections do not automatically use HTTP authentication, so we need to validate users manually.

  • Token is passed during connection
  • Server verifies the token
  • User data is stored in the socket
  • Invalid users are disconnected

Guard Implementation

import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { Socket } from 'socket.io';
@Injectable()
export class WsAuthGuard implements CanActivate {
  constructor(private jwtService: JwtService) {}
  canActivate(context: ExecutionContext): boolean {
    const client = context.switchToWs().getClient<Socket>();
    const token = client.handshake.auth?.token;
    if (!token) {
      client.disconnect();
      return false;
    }
    try {
      const decoded = this.jwtService.verify(token);
      client.data.user = decoded;
      return true;
    }
    catch {
      client.disconnect();
      return false;
    }
  }
}

Apply Guard

@UseGuards(WsAuthGuard)
@SubscribeMessage('sendMessage')
handleMessage(@ConnectedSocket() client: Socket) {
  const user = client.data.user;
}

How It Works

The client sends a token during the connection handshake. The guard extracts and verifies this token. If valid, user data is attached to the socket and becomes accessible in all event handlers. If invalid, the connection is terminated immediately.

DTO Validation

Validating incoming data is essential to maintain system reliability and avoid unexpected errors.

  • Prevents invalid inputs
  • Ensures correct data format
  • Uses class-validator with NestJS
  • Applied using validation pipes

DTO Example

import { IsString, IsNotEmpty } from 'class-validator';
export class SendMessageDto {
  @IsString()
  @IsNotEmpty()
  message: string;
  @IsString()
  @IsNotEmpty()
  roomId: string;
}

Apply Validation

@UsePipes(new ValidationPipe({ whitelist: true }))
@SubscribeMessage('sendMessage')
handleMessage(
  @MessageBody() dto: SendMessageDto,
  @ConnectedSocket() client: Socket,
) {
  this.server.to(dto.roomId).emit('receiveMessage', dto);
}

How It Works

The validation pipe automatically checks the incoming payload against the DTO. If the data does not match the expected structure, the request is rejected before reaching your business logic, keeping your system safe and consistent.

Error Handling

Handling errors properly ensures that the system does not crash and clients receive meaningful feedback.

Use try-catch blocks

  • Send structured error responses
  • Avoid breaking the connection
  • Keep the system stable

Example

@SubscribeMessage('sendMessage')
handleMessage(@MessageBody() data: any, @ConnectedSocket() client: Socket) {
  try {
    if (!data.message) {
      throw new Error('Message required');
    }
    this.server.emit('receiveMessage', data);
  } catch (error) {
    client.emit('error', {
      message: error.message,
    });
  }
}

How It Works

Errors are captured inside the handler and sent back to the client as events. This prevents crashes and allows the frontend to handle issues gracefully.

Real-World Example: Order System

Let’s combine all concepts into a real use case.

Scenario

  • User tracks an order
  • Backend updates order status
  • Only relevant users receive updates

Implementation

@SubscribeMessage('subscribeOrder')
handleSubscribe(
@MessageBody() data: { orderId: string },
@ConnectedSocket() client: Socket,
) {
  const room = `order_${data.orderId}`;
  client.join(room);
}
updateOrderStatus(orderId: string, status: string) {
  const room = `order_${orderId}`;
  this.server.to(room).emit('orderUpdate', {
    orderId,
    status,
  });
}

How It Works

Each order is treated as a room. Users interested in that order join the room. Whenever the order status changes, the server emits updates only to that room, ensuring efficient and targeted communication.

Performance Considerations

Efficient communication becomes critical as the number of users grows.

  • Avoid unnecessary global broadcasts
  • Use rooms for targeted messaging
  • Reduce event frequency when possible
  • Clean up disconnected clients

Example

this.server.to(roomId).emit('update', data); // efficient

Instead of:

this.server.emit('update', data); // inefficient

How It Works

Targeting specific rooms reduces network load and improves performance. Broadcasting to all users should only be used when absolutely necessary.

Summary

At this point, you’re not just using WebSockets, you’re understanding how to design real-time systems properly.

  • Rooms enable scalable communication by sending data only to relevant users instead of broadcasting to everyone
  • JWT authentication secures connections and ensures only valid users can interact with the system
  • DTO validation protects data flow by preventing invalid inputs from reaching business logic
  • Error handling keeps the system stable and avoids unexpected crashes during runtime
  • Proper structuring improves maintainability, aligning with NestJS architecture for long-term scalability

These patterns together form the base of a production-ready WebSocket system, not just a basic setup.

Final Note

With Part 1 and Part 2 combined, we now have a complete understanding of building real-time systems using WebSockets in NestJS.

We’re ready to implement:

  • Chat systems
  • Notification services
  • Order tracking systems
  • Live dashboards

The real value now comes from applying these concepts in actual projects. Once implemented, the flow and patterns will become much more intuitive, and you’ll be able to design efficient real-time features with confidence.

Enjoyed this guide? Drop your thoughts below — we’d love to hear them!

Brought to you by Pavankumar Patel from the Silversky Technology crew. Curious what else we’re building? Explore more at silverskytechnology.com.


메타데이터
post_id
0bd3de2282ed
slug
websockets-in-nestjs-part-2-0bd3de2282ed
url
https://medium.com/@silverskytechnology/websockets-in-nestjs-part-2-0bd3de2282ed
canonical_url
https://medium.com/@silverskytechnology/websockets-in-nestjs-part-2-0bd3de2282ed
author_url
https://medium.com/@silverskytechnology
status
ok
fetched_at
2026-06-09 15:37:30