NestJS and WebSockets in 2026: Real-Time, Gateway and Interview Questions
Master WebSockets in NestJS with Gateway patterns, Socket.IO integration, authentication, error handling and common interview questions for 2026.

NestJS WebSockets provide a structured approach to real-time communication using the Gateway pattern. Unlike raw WebSocket implementations, NestJS abstracts complexity through decorators and integrates seamlessly with the dependency injection system.
A WebSocket Gateway in NestJS is a class decorated with @WebSocketGateway() that handles bidirectional communication between client and server. It supports multiple adapters (Socket.IO, ws) and integrates with NestJS Guards, Pipes, and Interceptors.
Setting Up a WebSocket Gateway with Socket.IO
The default adapter in NestJS uses Socket.IO, which provides automatic reconnection, room support, and fallback to HTTP long-polling. Installation requires the platform-specific package alongside the core WebSockets module.
# terminal
npm install @nestjs/websockets @nestjs/platform-socket.io socket.ioA basic gateway listens for incoming messages and can broadcast responses to connected clients.
import {
WebSocketGateway,
WebSocketServer,
SubscribeMessage,
MessageBody,
ConnectedSocket,
} from '@nestjs/websockets';
import { Server, Socket } from 'socket.io';
@WebSocketGateway({
cors: { origin: '*' }, // Configure CORS for browser clients
})
export class ChatGateway {
@WebSocketServer()
server: Server; // Access to the underlying Socket.IO server
@SubscribeMessage('message') // Listen for 'message' events
handleMessage(
@MessageBody() data: { text: string; room: string },
@ConnectedSocket() client: Socket,
): void {
// Broadcast to all clients in the room except sender
client.to(data.room).emit('message', {
text: data.text,
senderId: client.id,
timestamp: Date.now(),
});
}
}The @SubscribeMessage decorator binds a method to a specific event name. The @MessageBody() extracts the payload, while @ConnectedSocket() provides access to the client socket for targeted responses.
Lifecycle Hooks for Connection Management
NestJS gateways implement lifecycle interfaces to handle client connections and disconnections. These hooks enable resource cleanup, presence tracking, and connection validation.
import {
WebSocketGateway,
OnGatewayConnection,
OnGatewayDisconnect,
OnGatewayInit,
} from '@nestjs/websockets';
import { Server, Socket } from 'socket.io';
import { Logger } from '@nestjs/common';
@WebSocketGateway()
export class PresenceGateway
implements OnGatewayInit, OnGatewayConnection, OnGatewayDisconnect
{
private readonly logger = new Logger(PresenceGateway.name);
private connectedUsers = new Map<string, { joinedAt: Date }>();
afterInit(server: Server): void {
// Called once when the gateway initializes
this.logger.log('WebSocket Gateway initialized');
}
handleConnection(client: Socket): void {
// Track new connections
this.connectedUsers.set(client.id, { joinedAt: new Date() });
this.logger.log(`Client connected: ${client.id}`);
}
handleDisconnect(client: Socket): void {
// Cleanup on disconnect
this.connectedUsers.delete(client.id);
this.logger.log(`Client disconnected: ${client.id}`);
}
}The three lifecycle interfaces serve distinct purposes: OnGatewayInit runs once at startup, OnGatewayConnection triggers per client connection, and OnGatewayDisconnect handles cleanup when clients leave.
Authentication with WebSocket Guards
WebSocket connections require authentication validation before allowing access to protected events. NestJS Guards work with gateways, though the execution context differs from HTTP requests. The official NestJS WebSockets documentation covers guard integration in detail.
import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';
import { WsException } from '@nestjs/websockets';
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: Socket = context.switchToWs().getClient();
// Extract token from handshake auth or query params
const token =
client.handshake.auth?.token ||
client.handshake.query?.token;
if (!token) {
throw new WsException('Missing authentication token');
}
try {
const payload = this.jwtService.verify(token as string);
// Attach user data to socket for later use
client.data.user = payload;
return true;
} catch {
throw new WsException('Invalid token');
}
}
}Apply the guard to the gateway class or individual message handlers using the @UseGuards() decorator. The WsException class throws errors that the client receives through the Socket.IO error event.
import { UseGuards } from '@nestjs/common';
import { WebSocketGateway, SubscribeMessage } from '@nestjs/websockets';
import { WsAuthGuard } from './ws-auth.guard';
@WebSocketGateway()
@UseGuards(WsAuthGuard) // Protect all handlers in this gateway
export class SecureChatGateway {
@SubscribeMessage('privateMessage')
handlePrivateMessage(): void {
// Only authenticated clients reach this handler
}
}For module-level authentication questions, explore the NestJS authentication interview module covering JWT strategies and session management.
Ready to ace your Node.js / NestJS interviews?
Practice with our interactive simulators, flashcards, and technical tests.
Room-Based Broadcasting Patterns
Socket.IO rooms enable targeted message delivery to subsets of connected clients. Common use cases include chat rooms, game lobbies, and live collaboration features.
import {
WebSocketGateway,
SubscribeMessage,
ConnectedSocket,
MessageBody,
WebSocketServer,
} from '@nestjs/websockets';
import { Server, Socket } from 'socket.io';
@WebSocketGateway()
export class RoomGateway {
@WebSocketServer()
server: Server;
@SubscribeMessage('joinRoom')
handleJoinRoom(
@MessageBody() roomId: string,
@ConnectedSocket() client: Socket,
): { event: string; data: string } {
// Add client to the specified room
client.join(roomId);
// Notify others in the room
client.to(roomId).emit('userJoined', { userId: client.id });
return { event: 'joinedRoom', data: roomId };
}
@SubscribeMessage('leaveRoom')
handleLeaveRoom(
@MessageBody() roomId: string,
@ConnectedSocket() client: Socket,
): void {
client.leave(roomId);
client.to(roomId).emit('userLeft', { userId: client.id });
}
@SubscribeMessage('roomBroadcast')
handleRoomBroadcast(
@MessageBody() payload: { roomId: string; message: string },
): void {
// Send to all clients in room, including sender
this.server.to(payload.roomId).emit('roomMessage', payload.message);
}
}The distinction between client.to(room).emit() and server.to(room).emit() matters: the former excludes the sender, while the latter includes all room members.
Error Handling with Exception Filters
WebSocket exceptions require dedicated filters since HTTP exception filters do not apply to gateway contexts. Custom filters catch WsException and format error responses for clients.
import { Catch, ArgumentsHost, ExceptionFilter } from '@nestjs/common';
import { WsException } from '@nestjs/websockets';
import { Socket } from 'socket.io';
@Catch(WsException)
export class WsExceptionFilter implements ExceptionFilter {
catch(exception: WsException, host: ArgumentsHost): void {
const client: Socket = host.switchToWs().getClient();
const error = exception.getError();
// Send structured error to client
client.emit('error', {
type: 'WsException',
message: typeof error === 'string' ? error : error,
timestamp: new Date().toISOString(),
});
}
}Apply filters at the gateway level for consistent error handling across all message handlers.
import { UseFilters } from '@nestjs/common';
import { WebSocketGateway } from '@nestjs/websockets';
import { WsExceptionFilter } from './ws-exception.filter';
@WebSocketGateway()
@UseFilters(WsExceptionFilter)
export class FilteredGateway {
// All handlers benefit from centralized error handling
}This pattern mirrors the NestJS philosophy of decorators and filters described in the middleware and interceptors module.
Scaling WebSockets with Redis Adapter
Single-server WebSocket deployments fail when load balancing distributes clients across multiple instances. The Socket.IO Redis adapter synchronizes events across instances through a pub/sub mechanism.
import { Module } from '@nestjs/common';
import { createAdapter } from '@socket.io/redis-adapter';
import { createClient } from 'redis';
import { ChatGateway } from './chat.gateway';
@Module({
providers: [
ChatGateway,
{
provide: 'REDIS_ADAPTER',
useFactory: async () => {
const pubClient = createClient({ url: process.env.REDIS_URL });
const subClient = pubClient.duplicate();
await Promise.all([pubClient.connect(), subClient.connect()]);
return createAdapter(pubClient, subClient);
},
},
],
})
export class AppModule {}The gateway then uses the adapter for cross-instance communication.
import {
WebSocketGateway,
WebSocketServer,
OnGatewayInit,
} from '@nestjs/websockets';
import { Inject } from '@nestjs/common';
import { Server } from 'socket.io';
import { Adapter } from 'socket.io-adapter';
@WebSocketGateway()
export class ScalableGateway implements OnGatewayInit {
@WebSocketServer()
server: Server;
constructor(@Inject('REDIS_ADAPTER') private redisAdapter: Adapter) {}
afterInit(): void {
// Attach Redis adapter for multi-instance support
this.server.adapter(this.redisAdapter as any);
}
}With the Redis adapter, a message emitted on one server instance reaches clients connected to any instance in the cluster.
Common Interview Questions on NestJS WebSockets
Technical interviews often probe understanding of real-time architecture decisions and NestJS-specific implementation details.
How does NestJS handle WebSocket authentication differently from HTTP?
HTTP middleware does not execute for WebSocket connections. Authentication happens during the handshake phase or through Guards applied to the gateway. Token validation typically occurs in handleConnection() or a custom Guard that reads from socket.handshake.auth.
What is the difference between @WebSocketGateway() port configuration and the main application port?
By default, WebSocket gateways share the HTTP server port. Specifying a port in @WebSocketGateway(3001) creates a separate WebSocket server on that port. Shared ports simplify deployment but require path-based routing (/socket.io) when using reverse proxies.
How do you test WebSocket gateways in NestJS?
NestJS testing utilities support gateway testing through Test.createTestingModule(). The socket.io-client library connects to the test server. Lifecycle hooks and message handlers are tested by emitting events and asserting on responses or side effects.
import { Test } from '@nestjs/testing';
import { INestApplication } from '@nestjs/common';
import { io, Socket } from 'socket.io-client';
import { ChatGateway } from './chat.gateway';
describe('ChatGateway', () => {
let app: INestApplication;
let client: Socket;
beforeAll(async () => {
const module = await Test.createTestingModule({
providers: [ChatGateway],
}).compile();
app = module.createNestApplication();
await app.listen(3000);
client = io('http://localhost:3000');
});
afterAll(async () => {
client.disconnect();
await app.close();
});
it('receives message acknowledgment', (done) => {
client.emit('message', { text: 'test', room: 'lobby' });
client.on('message', (data) => {
expect(data.text).toBe('test');
done();
});
});
});When should you use the ws adapter instead of Socket.IO?
The ws library adapter (@nestjs/platform-ws) offers lower overhead for applications that do not need Socket.IO features like automatic reconnection, rooms, or fallback transports. High-frequency trading systems and game servers often prefer ws for reduced latency.
For broader NestJS architecture concepts, the related article on Guards, Interceptors and Modular Architecture covers how these patterns integrate across HTTP and WebSocket contexts.
Conclusion
- WebSocket Gateways integrate with NestJS dependency injection, Guards, and Filters for consistent patterns across HTTP and real-time endpoints
- Lifecycle hooks (
OnGatewayConnection,OnGatewayDisconnect) manage presence tracking and resource cleanup - Authentication flows differ from HTTP; token validation happens during handshake or through dedicated WebSocket Guards
- Room-based broadcasting with Socket.IO enables targeted messaging without managing socket lists manually
- Redis adapter solves horizontal scaling by synchronizing events across multiple server instances
- Exception filters require WebSocket-specific implementations using
WsExceptionand custom filters
Start practicing!
Test your knowledge with our interview simulators and technical tests.
Share
Related articles

NestJS and GraphQL in 2026: Schemas, Resolvers and Interview Questions
Master NestJS GraphQL integration with schema-first and code-first approaches, resolver patterns, and common interview questions for senior developer positions.

NestJS and TypeORM in 2026: Migrations, Relations and Interview Questions
Master NestJS TypeORM integration with TypeORM 1.0 migrations, entity relations, repository patterns and common interview questions for backend developers.

Node.js 24 in 2026: URLPattern, Permissions Model and Interview Questions
Node.js 24 LTS brings a stable Permission Model, global URLPattern, explicit resource management with using/await using, and V8 13.6. A deep dive into the features that matter for production and interviews.