NestJS y WebSockets en 2026: Tiempo Real, Gateway y Preguntas de Entrevista

Domina WebSockets en NestJS con patrones Gateway, integración Socket.IO, autenticación, manejo de errores y preguntas comunes de entrevista para 2026.

Comunicación en tiempo real NestJS WebSocket con gateway

Los WebSockets de NestJS proporcionan un enfoque estructurado para la comunicación en tiempo real utilizando el patrón Gateway. A diferencia de las implementaciones WebSocket básicas, NestJS abstrae la complejidad mediante decoradores e integra perfectamente con el sistema de inyección de dependencias.

Definición Rápida

Un WebSocket Gateway en NestJS es una clase decorada con @WebSocketGateway() que maneja la comunicación bidireccional entre cliente y servidor. Soporta múltiples adaptadores (Socket.IO, ws) y se integra con Guards, Pipes e Interceptors de NestJS.

Configuración de un WebSocket Gateway con Socket.IO

El adaptador predeterminado en NestJS utiliza Socket.IO, que proporciona reconexión automática, soporte para rooms y fallback a HTTP long-polling. La instalación requiere el paquete específico de la plataforma junto con el módulo principal de WebSockets.

bash
# terminal
npm install @nestjs/websockets @nestjs/platform-socket.io socket.io

Un gateway básico escucha mensajes entrantes y puede transmitir respuestas a los clientes conectados.

chat.gateway.tstypescript
import {
  WebSocketGateway,
  WebSocketServer,
  SubscribeMessage,
  MessageBody,
  ConnectedSocket,
} from '@nestjs/websockets';
import { Server, Socket } from 'socket.io';

@WebSocketGateway({
  cors: { origin: '*' }, // Configura CORS para clientes del navegador
})
export class ChatGateway {
  @WebSocketServer()
  server: Server; // Acceso al servidor Socket.IO subyacente

  @SubscribeMessage('message') // Escucha eventos 'message'
  handleMessage(
    @MessageBody() data: { text: string; room: string },
    @ConnectedSocket() client: Socket,
  ): void {
    // Transmite a todos los clientes en la room excepto el remitente
    client.to(data.room).emit('message', {
      text: data.text,
      senderId: client.id,
      timestamp: Date.now(),
    });
  }
}

El decorador @SubscribeMessage vincula un método a un nombre de evento específico. @MessageBody() extrae el payload, mientras que @ConnectedSocket() proporciona acceso al socket del cliente para respuestas dirigidas.

Hooks del Ciclo de Vida para Gestión de Conexiones

Los gateways de NestJS implementan interfaces de ciclo de vida para manejar conexiones y desconexiones de clientes. Estos hooks permiten la limpieza de recursos, seguimiento de presencia y validación de conexiones.

presence.gateway.tstypescript
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 {
    // Se llama una vez cuando el gateway se inicializa
    this.logger.log('WebSocket Gateway inicializado');
  }

  handleConnection(client: Socket): void {
    // Rastrea nuevas conexiones
    this.connectedUsers.set(client.id, { joinedAt: new Date() });
    this.logger.log(`Cliente conectado: ${client.id}`);
  }

  handleDisconnect(client: Socket): void {
    // Limpieza al desconectar
    this.connectedUsers.delete(client.id);
    this.logger.log(`Cliente desconectado: ${client.id}`);
  }
}

Las tres interfaces de ciclo de vida sirven propósitos distintos: OnGatewayInit se ejecuta una vez al inicio, OnGatewayConnection se activa por cada conexión de cliente, y OnGatewayDisconnect maneja la limpieza cuando los clientes se van.

Autenticación con Guards de WebSocket

Las conexiones WebSocket requieren validación de autenticación antes de permitir acceso a eventos protegidos. Los Guards de NestJS funcionan con gateways, aunque el contexto de ejecución difiere de las solicitudes HTTP. La documentación oficial de WebSockets de NestJS cubre la integración de guards en detalle.

ws-auth.guard.tstypescript
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();
    // Extrae el token del handshake auth o query params
    const token =
      client.handshake.auth?.token ||
      client.handshake.query?.token;

    if (!token) {
      throw new WsException('Token de autenticación faltante');
    }

    try {
      const payload = this.jwtService.verify(token as string);
      // Adjunta datos del usuario al socket para uso posterior
      client.data.user = payload;
      return true;
    } catch {
      throw new WsException('Token inválido');
    }
  }
}

El guard se aplica a la clase gateway o a handlers de mensajes individuales usando el decorador @UseGuards(). La clase WsException lanza errores que el cliente recibe a través del evento error de Socket.IO.

secure-chat.gateway.tstypescript
import { UseGuards } from '@nestjs/common';
import { WebSocketGateway, SubscribeMessage } from '@nestjs/websockets';
import { WsAuthGuard } from './ws-auth.guard';

@WebSocketGateway()
@UseGuards(WsAuthGuard) // Protege todos los handlers en este gateway
export class SecureChatGateway {
  @SubscribeMessage('privateMessage')
  handlePrivateMessage(): void {
    // Solo clientes autenticados llegan a este handler
  }
}

Para preguntas de autenticación a nivel de módulo, consulta el módulo de entrevista de autenticación y JWT de NestJS que cubre estrategias JWT y gestión de sesiones.

¿Listo para aprobar tus entrevistas de Node.js / NestJS?

Practica con nuestros simuladores interactivos, flashcards y tests técnicos.

Patrones de Broadcasting Basados en Rooms

Las rooms de Socket.IO permiten la entrega dirigida de mensajes a subconjuntos de clientes conectados. Los casos de uso comunes incluyen salas de chat, lobbies de juegos y funciones de colaboración en vivo.

room.gateway.tstypescript
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 } {
    // Agrega el cliente a la room especificada
    client.join(roomId);
    // Notifica a otros en la 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 {
    // Envía a todos los clientes en la room, incluyendo al remitente
    this.server.to(payload.roomId).emit('roomMessage', payload.message);
  }
}

La distinción entre client.to(room).emit() y server.to(room).emit() es importante: el primero excluye al remitente, mientras que el segundo incluye a todos los miembros de la room.

Manejo de Errores con Filtros de Excepción

Las excepciones WebSocket requieren filtros dedicados ya que los filtros de excepción HTTP no aplican a contextos de gateway. Los filtros personalizados capturan WsException y formatean respuestas de error para los clientes.

ws-exception.filter.tstypescript
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();
    // Envía error estructurado al cliente
    client.emit('error', {
      type: 'WsException',
      message: typeof error === 'string' ? error : error,
      timestamp: new Date().toISOString(),
    });
  }
}

Los filtros se aplican a nivel de gateway para un manejo consistente de errores en todos los handlers de mensajes.

filtered.gateway.tstypescript
import { UseFilters } from '@nestjs/common';
import { WebSocketGateway } from '@nestjs/websockets';
import { WsExceptionFilter } from './ws-exception.filter';

@WebSocketGateway()
@UseFilters(WsExceptionFilter)
export class FilteredGateway {
  // Todos los handlers se benefician del manejo centralizado de errores
}

Este patrón refleja la filosofía de NestJS de decoradores y filtros descrita en el módulo de middleware e interceptors.

Escalando WebSockets con Adaptador Redis

Los despliegues WebSocket de un solo servidor fallan cuando el balanceo de carga distribuye clientes entre múltiples instancias. El adaptador Redis de Socket.IO sincroniza eventos entre instancias a través de un mecanismo pub/sub.

app.module.tstypescript
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 {}

El gateway luego usa el adaptador para comunicación entre instancias.

scalable.gateway.tstypescript
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 {
    // Adjunta el adaptador Redis para soporte multi-instancia
    this.server.adapter(this.redisAdapter as any);
  }
}

Con el adaptador Redis, un mensaje emitido en una instancia del servidor llega a los clientes conectados a cualquier instancia del cluster.

Preguntas Comunes de Entrevista sobre WebSockets en NestJS

Las entrevistas técnicas frecuentemente exploran la comprensión de decisiones de arquitectura en tiempo real y detalles de implementación específicos de NestJS.

Frecuentemente Preguntado

¿Cómo maneja NestJS la autenticación WebSocket de manera diferente a HTTP?

El middleware HTTP no se ejecuta para conexiones WebSocket. La autenticación ocurre durante la fase de handshake o a través de Guards aplicados al gateway. La validación del token típicamente ocurre en handleConnection() o un Guard personalizado que lee desde socket.handshake.auth.

¿Cuál es la diferencia entre la configuración de puerto de @WebSocketGateway() y el puerto principal de la aplicación?

Por defecto, los gateways WebSocket comparten el puerto del servidor HTTP. Especificar un puerto en @WebSocketGateway(3001) crea un servidor WebSocket separado en ese puerto. Los puertos compartidos simplifican el despliegue pero requieren enrutamiento basado en rutas (/socket.io) al usar proxies reversos.

¿Cómo se prueban los gateways WebSocket en NestJS?

Las utilidades de testing de NestJS soportan pruebas de gateway a través de Test.createTestingModule(). La biblioteca socket.io-client se conecta al servidor de pruebas. Los hooks de ciclo de vida y handlers de mensajes se prueban emitiendo eventos y verificando respuestas o efectos secundarios.

chat.gateway.spec.tstypescript
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('recibe confirmación de mensaje', (done) => {
    client.emit('message', { text: 'test', room: 'lobby' });
    client.on('message', (data) => {
      expect(data.text).toBe('test');
      done();
    });
  });
});

¿Cuándo usar el adaptador ws en lugar de Socket.IO?

El adaptador de la biblioteca ws (@nestjs/platform-ws) ofrece menor overhead para aplicaciones que no necesitan características de Socket.IO como reconexión automática, rooms o transportes de fallback. Los sistemas de trading de alta frecuencia y servidores de juegos a menudo prefieren ws por su latencia reducida.

Para conceptos más amplios de arquitectura NestJS, el artículo relacionado sobre Guards, Interceptors y Arquitectura Modular cubre cómo estos patrones se integran a través de contextos HTTP y WebSocket.

Conclusión

  • Los WebSocket Gateways se integran con inyección de dependencias, Guards y Filters de NestJS para patrones consistentes entre HTTP y endpoints de tiempo real
  • Los hooks de ciclo de vida (OnGatewayConnection, OnGatewayDisconnect) gestionan el seguimiento de presencia y limpieza de recursos
  • Los flujos de autenticación difieren de HTTP; la validación del token ocurre durante el handshake o a través de Guards WebSocket dedicados
  • El broadcasting basado en rooms con Socket.IO permite mensajería dirigida sin gestionar listas de sockets manualmente
  • El adaptador Redis resuelve el escalado horizontal sincronizando eventos entre múltiples instancias del servidor
  • Los filtros de excepción requieren implementaciones específicas de WebSocket usando WsException y filtros personalizados

¡Empieza a practicar!

Pon a prueba tu conocimiento con nuestros simuladores de entrevista y tests técnicos.

Anthony Fillion-Maillet

Escrito por

Anthony Fillion-Maillet

Desarrollador fullstack, fundador de SharpSkill

Desarrollador fullstack desde hace más de 10 años. Dirige SharpSkill y responde por todo lo que se publica aquí.

Actualizado el 10 de agosto de 2026

Compartir

Artículos relacionados