# How to Implement WebSocket Gateways in NestJS: A Complete Developer Guide

> Master NestJS WebSocket gateways. Learn to create gateways, handle messages with SubscribeMessage, and manage connections for real-time applications. Your complete developer guide.

- Repository: [nestjs/nest](https://github.com/nestjs/nest)
- Tags: how-to-guide
- Published: 2026-03-01

---

**You implement WebSocket gateways in NestJS by creating a class decorated with `@WebSocketGateway()`, defining message handlers with `@SubscribeMessage()`, and optionally implementing lifecycle hooks like `OnGatewayInit` and `OnGatewayConnection` to manage server events and client connections.**

NestJS provides first-class support for real-time communication through its WebSockets module, allowing developers to implement WebSocket gateways using a decorator-based approach similar to HTTP controllers. By leveraging decorators like `@WebSocketGateway()` and `@SubscribeMessage()`, you can create type-safe, scalable socket servers that integrate seamlessly with the NestJS dependency injection system. This guide examines the actual source code from the `nestjs/nest` repository to explain how gateways function internally and how to build production-ready implementations.

## What Is a WebSocket Gateway in NestJS?

A **WebSocket gateway** in NestJS is a provider class that encapsulates a real-time server instance (such as Socket.IO) and defines methods to handle incoming socket messages. Unlike HTTP controllers that handle request-response cycles, gateways maintain persistent connections with clients and communicate through events.

The foundation of every gateway is the `@WebSocketGateway()` decorator, which marks the class for the NestJS runtime. According to the source code in [`packages/websockets/decorators/socket-gateway.decorator.ts`](https://github.com/nestjs/nest/blob/main/packages/websockets/decorators/socket-gateway.decorator.ts), this decorator attaches three critical metadata keys to the class:

- **`GATEWAY_METADATA`** – Flags the class as a WebSocket gateway
- **`PORT_METADATA`** – Specifies the listening port (defaults to `0`)
- **`GATEWAY_OPTIONS`** – Stores optional configuration objects

These metadata keys are defined in [`packages/websockets/constants.ts`](https://github.com/nestjs/nest/blob/main/packages/websockets/constants.ts) and consumed by the runtime to configure the server instance.

```typescript
// https://github.com/nestjs/nest/blob/master/packages/websockets/decorators/socket-gateway.decorator.ts#L20-L28
Reflect.defineMetadata(GATEWAY_METADATA, true, target);
Reflect.defineMetadata(PORT_METADATA, port, target);
Reflect.defineMetadata(GATEWAY_OPTIONS, opt, target);

```

## Core Architecture and Metadata System

The runtime behavior of WebSocket gateways is orchestrated by the `WebSocketsController` class located in [`packages/websockets/web-sockets-controller.ts`](https://github.com/nestjs/nest/blob/main/packages/websockets/web-sockets-controller.ts). This controller scans for gateway classes, extracts their metadata, and wires them to the underlying socket server.

### Message Mapping Metadata

Individual methods within a gateway are bound to specific message patterns using the `@SubscribeMessage()` decorator. As implemented in [`packages/websockets/decorators/subscribe-message.decorator.ts`](https://github.com/nestjs/nest/blob/main/packages/websockets/decorators/subscribe-message.decorator.ts), this decorator attaches:

- **`MESSAGE_MAPPING_METADATA`** – Marks the method as a message handler
- **`MESSAGE_METADATA`** – Stores the message pattern string

```typescript
// https://github.com/nestjs/nest/blob/master/packages/websockets/decorators/subscribe-message.decorator.ts#L14-L16
Reflect.defineMetadata(MESSAGE_MAPPING_METADATA, true, descriptor.value);
Reflect.defineMetadata(MESSAGE_METADATA, message, descriptor.value);

```

### Controller Initialization Process

When the NestJS application boots, the `WebSocketsController` executes the following steps for each discovered gateway:

1. **Metadata Retrieval** – Calls `Reflect.getMetadata` to extract `GATEWAY_OPTIONS` and `PORT_METADATA` (see lines 45-55 in [`web-sockets-controller.ts`](https://github.com/nestjs/nest/blob/main/web-sockets-controller.ts))
2. **Server Instantiation** – Creates a socket server via `SocketServerProvider` on the configured port
3. **Handler Discovery** – Scans the gateway instance for methods marked with `MESSAGE_MAPPING_METADATA`
4. **Event Wiring** – Binds lifecycle hooks (`afterInit`, `handleConnection`, `handleDisconnect`) through dedicated subscription methods: `subscribeInitEvent`, `subscribeConnectionEvent`, and `subscribeDisconnectEvent`

```typescript
// https://github.com/nestjs/nest/blob/master/packages/websockets/web-sockets-controller.ts#L45-L55
const options = Reflect.getMetadata(GATEWAY_OPTIONS, metatype) || {};
const port = Reflect.getMetadata(PORT_METADATA, metatype) || 0;

```

### Message Execution Flow

When a client emits a message matching a registered pattern, the controller retrieves the appropriate handler via `subscribeMessages`. The handler is bound to the client context and executed, with the return value automatically wrapped into an `Observable` to support promises, streams, or plain values.

```typescript
// https://github.com/nestjs/nest/blob/master/packages/websockets/web-sockets-controller.ts#L85-L87
const handlers = subscribersMap.map(({ callback, message, isAckHandledManually }) => ({
  message,
  callback: callback.bind(instance, client),
  isAckHandledManually,
}));

```

## Implementing a Basic WebSocket Gateway

To implement a simple gateway that responds to client messages, create a class decorated with `@WebSocketGateway()` and define handler methods using `@SubscribeMessage()`.

```typescript
// src/app.gateway.ts
import {
  WebSocketGateway,
  SubscribeMessage,
  MessageBody,
} from '@nestjs/websockets';

@WebSocketGateway(3001)  // Optional: specify port
export class AppGateway {
  @SubscribeMessage('ping')
  handlePing(@MessageBody() data: any) {
    return { event: 'pong', data };
  }
}

```

The `@WebSocketGateway(3001)` decorator registers this class to listen on port 3001, storing this value in `PORT_METADATA`. The `handlePing` method binds to the `"ping"` message pattern through `MESSAGE_METADATA`, allowing the `WebSocketsController` to route incoming "ping" events to this specific handler.

## Handling Lifecycle Events in Your Gateway

Production gateways often require logic to execute when clients connect, disconnect, or when the server initializes. NestJS provides three optional interfaces: `OnGatewayInit`, `OnGatewayConnection`, and `OnGatewayDisconnect`.

When a gateway implements these interfaces, the `WebSocketsController` automatically subscribes to the corresponding server events through its internal `subscribeInitEvent`, `subscribeConnectionEvent`, and `subscribeDisconnectEvent` methods.

```typescript
// src/chat.gateway.ts
import {
  WebSocketGateway,
  SubscribeMessage,
  ConnectedSocket,
  MessageBody,
  OnGatewayInit,
  OnGatewayConnection,
  OnGatewayDisconnect,
} from '@nestjs/websockets';
import { Server, Socket } from 'socket.io';

@WebSocketGateway()
export class ChatGateway implements OnGatewayInit, OnGatewayConnection, OnGatewayDisconnect {
  private server: Server;

  afterInit(server: Server) {
    this.server = server;
    console.log('WebSocket server initialized');
  }

  handleConnection(client: Socket) {
    console.log(`Client connected: ${client.id}`);
  }

  handleDisconnect(client: Socket) {
    console.log(`Client disconnected: ${client.id}`);
  }

  @SubscribeMessage('message')
  handleMessage(
    @MessageBody() payload: string,
    @ConnectedSocket() client: Socket,
  ) {
    // Broadcast to all connected clients
    this.server.emit('message', payload);
  }
}

```

The `afterInit` method receives the server instance immediately after creation, while `handleConnection` and `handleDisconnect` receive the specific `Socket` client object for connection management.

## Advanced Patterns: Interceptors, Filters, and Error Handling

NestJS WebSocket gateways support the same interceptor and exception filter patterns as HTTP controllers, enabling cross-cutting concerns like logging, transformation, and error handling.

The following implementation from [`integration/websockets/src/app.gateway.ts`](https://github.com/nestjs/nest/blob/main/integration/websockets/src/app.gateway.ts) demonstrates a production-ready gateway with error handling using `WsException`, request interceptors, and exception filters:

```typescript
// src/app.gateway.ts
import {
  WebSocketGateway,
  SubscribeMessage,
  MessageBody,
  UseFilters,
  UseInterceptors,
  ConnectedSocket,
} from '@nestjs/websockets';
import { WsException } from '@nestjs/websockets';
import { RequestInterceptor } from './request.interceptor';
import { RequestFilter } from './request.filter';
import { throwError } from 'rxjs';

@WebSocketGateway(8080)
export class ApplicationGateway {
  @SubscribeMessage('push')
  onPush(@MessageBody() data: any) {
    return { event: 'pop', data };
  }

  @UseInterceptors(RequestInterceptor)
  @SubscribeMessage('getClient')
  getPathCalled(@ConnectedSocket() client: any, @MessageBody() data: any) {
    return { event: 'popClient', data: { ...data, path: client.pattern } };
  }

  @UseFilters(RequestFilter)
  @SubscribeMessage('getClientWithError')
  getPathCalledWithError() {
    return throwError(() => new WsException('This is an error'));
  }
}

```

**Key implementation details:**
- **`@UseInterceptors(RequestInterceptor)`** – Applies interceptors to transform requests or responses for specific message handlers
- **`@UseFilters(RequestFilter)`** – Catches exceptions thrown within the handler using the `WsException` class
- **`throwError` with `WsException`** – Returns an RxJS stream that emits an error, which the controller wraps and handles appropriately

## Summary

Implementing WebSocket gateways in NestJS involves understanding the framework's metadata-driven architecture and lifecycle management:

- **Decorator Metadata** – The `@WebSocketGateway()` decorator in [`packages/websockets/decorators/socket-gateway.decorator.ts`](https://github.com/nestjs/nest/blob/main/packages/websockets/decorators/socket-gateway.decorator.ts) stores `GATEWAY_METADATA`, `PORT_METADATA`, and `GATEWAY_OPTIONS` to configure the server instance
- **Message Mapping** – The `@SubscribeMessage()` decorator in [`packages/websockets/decorators/subscribe-message.decorator.ts`](https://github.com/nestjs/nest/blob/main/packages/websockets/decorators/subscribe-message.decorator.ts) attaches `MESSAGE_MAPPING_METADATA` and `MESSAGE_METADATA` to bind methods to specific socket events
- **Runtime Wiring** – The `WebSocketsController` in [`packages/websockets/web-sockets-controller.ts`](https://github.com/nestjs/nest/blob/main/packages/websockets/web-sockets-controller.ts) orchestrates server creation, handler discovery, and lifecycle event subscription through methods like `connectGatewayToServer` and `subscribeToServerEvents`
- **Lifecycle Hooks** – Implement `OnGatewayInit`, `OnGatewayConnection`, and `OnGatewayDisconnect` to hook into server initialization and client connection events
- **Advanced Features** – Apply interceptors with `@UseInterceptors()` and handle errors using `WsException` combined with `@UseFilters()` for robust message processing

## Frequently Asked Questions

### What port does a NestJS WebSocket gateway use by default?

By default, a NestJS WebSocket gateway listens on port `0`, which typically assigns a random available port. The `WebSocketsController` retrieves this value from `PORT_METADATA` (defined in [`packages/websockets/decorators/socket-gateway.decorator.ts`](https://github.com/nestjs/nest/blob/main/packages/websockets/decorators/socket-gateway.decorator.ts)), defaulting to `0` if no port is specified in the `@WebSocketGateway()` decorator options.

### How does NestJS map incoming socket messages to gateway methods?

NestJS maps messages through metadata scanning. When a message arrives, the `WebSocketsController` locates handlers marked with `MESSAGE_MAPPING_METADATA` (set by `@SubscribeMessage()` in [`packages/websockets/decorators/subscribe-message.decorator.ts`](https://github.com/nestjs/nest/blob/main/packages/websockets/decorators/subscribe-message.decorator.ts)) and matches the incoming pattern against `MESSAGE_METADATA`. The controller then binds the handler to the client instance and executes it, wrapping the result in an `Observable` to support asynchronous responses.

### What lifecycle hooks are available for WebSocket gateways in NestJS?

NestJS provides three primary lifecycle interfaces: `OnGatewayInit` (triggered via `subscribeInitEvent`), `OnGatewayConnection` (triggered via `subscribeConnectionEvent`), and `OnGatewayDisconnect` (triggered via `subscribeDisconnectEvent`). These are implemented in [`packages/websockets/web-sockets-controller.ts`](https://github.com/nestjs/nest/blob/main/packages/websockets/web-sockets-controller.ts) and allow you to execute logic when the server starts, when clients connect, and when clients disconnect respectively.

### How can I handle errors in WebSocket message handlers?

You can handle errors by throwing `WsException` from the `@nestjs/websockets` package and applying `@UseFilters()` with a custom exception filter to the handler method. As shown in the [`integration/websockets/src/app.gateway.ts`](https://github.com/nestjs/nest/blob/main/integration/websockets/src/app.gateway.ts) example, returning `throwError(() => new WsException('error message'))` creates an observable error stream that the controller processes through the registered filter, allowing you to format error responses consistently.