typescript 66 lines · 8 steps

Building a real-time chat gateway in NestJS

A NestJS WebSocket gateway that handles connections, room joins, and message broadcasting over Socket.IO.

Explained by highlit
1import {
2 WebSocketGateway,
3 WebSocketServer,
4 SubscribeMessage,
5 MessageBody,
6 ConnectedSocket,
7 OnGatewayConnection,
8 OnGatewayDisconnect,
9} from '@nestjs/websockets';
10import { Server, Socket } from 'socket.io';
11import { Logger, UseGuards } from '@nestjs/common';
12import { WsJwtGuard } from './guards/ws-jwt.guard';
13import { ChatService } from './chat.service';
14import { JoinRoomDto, SendMessageDto } from './dto';
15 
16@WebSocketGateway({
17 namespace: '/chat',
18 cors: { origin: process.env.CLIENT_URL, credentials: true },
19})
20export class ChatGateway implements OnGatewayConnection, OnGatewayDisconnect {
21 @WebSocketServer()
22 private readonly server: Server;
23 
24 private readonly logger = new Logger(ChatGateway.name);
25 
26 constructor(private readonly chatService: ChatService) {}
27 
28 handleConnection(client: Socket) {
29 this.logger.log(`Client connected: ${client.id}`);
30 }
31 
32 handleDisconnect(client: Socket) {
33 this.chatService.markOffline(client.id);
34 this.logger.log(`Client disconnected: ${client.id}`);
35 }
36 
37 @UseGuards(WsJwtGuard)
38 @SubscribeMessage('room:join')
39 async onJoinRoom(
40 @MessageBody() { roomId }: JoinRoomDto,
41 @ConnectedSocket() client: Socket,
42 ) {
43 await client.join(roomId);
44 const history = await this.chatService.recentMessages(roomId);
45 client.emit('room:history', history);
46 client.to(roomId).emit('room:presence', { userId: client.data.userId, online: true });
47 }
48 
49 @UseGuards(WsJwtGuard)
50 @SubscribeMessage('message:send')
51 async onMessage(
52 @MessageBody() dto: SendMessageDto,
53 @ConnectedSocket() client: Socket,
54 ) {
55 const message = await this.chatService.persist({
56 ...dto,
57 authorId: client.data.userId,
58 });
59 this.server.to(dto.roomId).emit('message:new', message);
60 return { status: 'delivered', id: message.id };
61 }
62 
63 broadcastAnnouncement(text: string) {
64 this.server.emit('system:announcement', { text, at: new Date().toISOString() });
65 }
66}
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1A gateway maps socket events to methods with decorators, keeping transport wiring out of your handlers.
  2. 2Rooms let you target broadcasts precisely — to one client, everyone but the sender, or the whole namespace.
  3. 3Guards secure individual socket events just like they secure HTTP routes.

Related explainers

typescript
import { registerLocaleData } from '@angular/common';
import localeFr from '@angular/common/locales/fr';
import localeFrExtra from '@angular/common/locales/extra/fr';
import localeDe from '@angular/common/locales/de';

Locale-aware bootstrapping in Angular

i18n localization dependency-injection
Intermediate 8 steps
python
from fastapi import FastAPI, WebSocket, WebSocketDisconnect
 
app = FastAPI()
 

Building a WebSocket chat with FastAPI

websockets broadcast connection-management
Intermediate 9 steps
typescript
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import * as Joi from 'joi';
 

Validating env config at boot in NestJS

configuration schema-validation environment-variables
Intermediate 8 steps
python
import time
import uuid
 
from django.utils.deprecation import MiddlewareMixin

Attaching per-request context in Django

middleware request lifecycle multi-tenancy
Intermediate 7 steps
typescript
import { Inject, Injectable, Logger } from '@nestjs/common';
import { CACHE_MANAGER } from '@nestjs/cache-manager';
import { Cache } from 'cache-manager';
import { InjectRepository } from '@nestjs/typeorm';

A cache-aside country lookup in NestJS

cache-aside dependency-injection batch-lookup
Intermediate 8 steps
typescript
import { Injectable, effect, signal, computed } from '@angular/core';
 
interface Preferences {
  theme: 'light' | 'dark';

A signal-based preferences store in Angular

signals state-management persistence
Intermediate 7 steps

Share this explainer

Here's the card — post it anywhere.

Building a real-time chat gateway in NestJS — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code