# How to Implement Microservices with NestJS: A Complete Guide to TCP, Redis, and Beyond

> Learn to implement microservices with NestJS using `NestFactory.createMicroservice` and decorators like `MessagePattern`. Build robust, scalable applications efficiently.

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

---

**To implement microservices with NestJS, use `NestFactory.createMicroservice()` to bootstrap a transport-agnostic server, decorate handlers with `@MessagePattern` or `@EventPattern`, and inject `ClientProxy` instances via the `@Client()` decorator or `ClientsModule` for inter-service communication.**

NestJS treats microservices as first-class citizens within the `nestjs/nest` ecosystem. The framework's `@nestjs/microservices` package provides a complete toolkit for building distributed systems using various transport layers including TCP, Redis, NATS, Kafka, and gRPC. Understanding the core architecture—specifically how the `ListenersController` registers pattern handlers and how the IoC container manages client proxies—is essential for production-grade implementations.

## Bootstrapping a Microservice Application

Instead of the standard HTTP bootstrap using `NestFactory.create()`, microservices require `NestFactory.createMicroservice()` or a hybrid approach using `createNestApplication()` combined with `connectMicroservice()`.

```typescript
// main.ts
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { Transport } from '@nestjs/microservices';

async function bootstrap() {
  const app = await NestFactory.createMicroservice(AppModule, {
    transport: Transport.TCP,
    options: { host: '0.0.0.0', port: 8877 },
  });
  await app.listen();
}
bootstrap();

```

The transport configuration determines which concrete `Server` implementation (such as `ServerTCP`, `ServerRedis`, or `ServerNATS`) the framework instantiates. These implementations adhere to the generic `Server` interface defined in [`packages/microservices/server/server.ts`](https://github.com/nestjs/nest/blob/main/packages/microservices/server/server.ts), ensuring consistent behavior across different messaging systems.

Alternatively, create a hybrid application that handles both HTTP and microservice traffic:

```typescript
const app = await NestFactory.create(AppModule);
const microservice = app.connectMicroservice({
  transport: Transport.TCP,
  options: { port: 8877 },
});
await app.startAllMicroservices();
await app.listen(3000);

```

## Registering Message Handlers with Decorators

Controllers in microservices use `@MessagePattern()` for request-response RPC flows or `@EventPattern()` for event-driven architectures. The `ListenersController` in [`packages/microservices/listeners-controller.ts`](https://github.com/nestjs/nest/blob/main/packages/microservices/listeners-controller.ts) orchestrates the registration of these handlers during application initialization.

**Pattern scanning process:**
- `MetadataScanner` inspects controller metadata
- `ListenerMetadataExplorer` identifies decorated methods
- `registerPatternHandlers()` (lines 61-78) binds patterns to the underlying `Server` instance

```typescript
// app.controller.ts
import { Controller } from '@nestjs/common';
import { MessagePattern, EventPattern } from '@nestjs/microservices';

@Controller()
export class AppController {
  @MessagePattern({ cmd: 'sum' })
  sum(data: number[]): number {
    return (data || []).reduce((a, b) => a + b);
  }

  @EventPattern('user_created')
  async handleUserCreated(data: Record<string, any>) {
    // Event-driven logic here
  }
}

```

Source: [app.controller.ts](https://github.com/nestjs/nest/blob/master/integration/microservices/src/tcp-tls/app.controller.ts)

## Injecting Client Proxies for Inter-Service Communication

Microservices communicate through `ClientProxy` instances, which abstract the underlying transport protocol. NestJS provides two injection mechanisms: the property decorator `@Client()` for simple cases and `ClientsModule` for complex, asynchronous configurations.

**Method 1: Using the `@Client()` decorator**

The `@Client()` decorator in [`packages/microservices/decorators/client.decorator.ts`](https://github.com/nestjs/nest/blob/main/packages/microservices/decorators/client.decorator.ts) marks properties for proxy injection. During initialization, `ListenersController.assignClientsToProperties()` (lines 4-16) creates clients via `ClientProxyFactory` and stores them in the `ClientsContainer`.

```typescript
import { Controller, Post, Body } from '@nestjs/common';
import { Client, ClientProxy, Transport } from '@nestjs/microservices';
import { first } from 'rxjs/operators';

@Controller()
export class AppController {
  @Client({ transport: Transport.TCP })
  client: ClientProxy;

  @Post('add')
  async add(@Body() numbers: number[]): Promise<number> {
    return this.client
      .send<number>({ cmd: 'sum' }, numbers)
      .pipe(first())
      .toPromise();
  }
}

```

**Method 2: Using `ClientsModule` for async configuration**

For dynamic configurations requiring dependency injection (such as environment-based transport settings), use `ClientsModule.registerAsync()`:

```typescript
// app.module.ts
import { Module, Injectable } from '@nestjs/common';
import { ClientsModule, Transport, ClientOptions, ClientsModuleOptionsFactory } from '@nestjs/microservices';
import { ConfigService } from './config.service';

@Injectable()
class ClientOptionService implements ClientsModuleOptionsFactory {
  constructor(private readonly config: ConfigService) {}
  createClientOptions(): ClientOptions {
    return { 
      transport: this.config.get('transport'), 
      options: this.config.get('transportOptions') 
    };
  }
}

@Module({
  imports: [
    ClientsModule.registerAsync([
      {
        name: 'ASYNC_CLIENT',
        imports: [ConfigModule],
        useClass: ClientOptionService,
      },
    ]),
  ],
  controllers: [AppController],
})
export class AppModule {}

```

Source: [app.module.ts](https://github.com/nestjs/nest/blob/master/integration/microservices/src/app.module.ts)

## Request-Scoped Providers and Error Handling

**Request-scoped handling**: For providers requiring request-scoped lifetime, the `ListenersController` creates unique execution contexts per message. The `createRequestScopedHandler` method (lines 24-32) generates a distinct `ContextId` for each incoming message, resolves the provider instance within that context, and ensures proper cleanup after execution.

**Error handling**: Exceptions thrown within message handlers propagate through `ExceptionFiltersContext`, mirroring NestJS's HTTP exception filter pipeline. Use `RpcException` to standardize error serialization across transport boundaries:

```typescript
import { RpcException } from '@nestjs/microservices';

@MessagePattern({ cmd: 'divide' })
divide(data: { a: number; b: number }) {
  if (data.b === 0) {
    throw new RpcException('Division by zero');
  }
  return data.a / data.b;
}

```

## Summary

- **Bootstrap**: Use `NestFactory.createMicroservice()` with a transport configuration (TCP, Redis, NATS, Kafka, etc.) to instantiate the appropriate `Server` implementation.
- **Handlers**: Decorate controller methods with `@MessagePattern` (RPC) or `@EventPattern` (events); the `ListenersController.registerPatternHandlers()` method wires these to the transport layer.
- **Clients**: Inject `ClientProxy` via `@Client()` for simple cases or `ClientsModule.registerAsync()` for dynamic configurations; `ClientProxyFactory` handles instantiation.
- **Scope**: Request-scoped providers are supported via `createRequestScopedHandler()` with unique `ContextId` generation per message.
- **Errors**: Use `RpcException` for transport-agnostic error handling processed by `ExceptionFiltersContext`.

## Frequently Asked Questions

### What transports does NestJS microservices support?

NestJS supports TCP, Redis, NATS, Kafka, RabbitMQ (RMQ), MQTT, and gRPC through the `@nestjs/microservices` package. Each transport implements the generic `Server` interface, allowing you to switch between messaging systems without changing your handler logic.

### How do I create a hybrid application that accepts both HTTP and microservice requests?

Use `NestFactory.create()` to create your standard HTTP application, then call `app.connectMicroservice()` with your transport configuration. Finally, invoke `app.startAllMicroservices()` before `app.listen()` to initialize both servers within the same process.

### What is the difference between `@MessagePattern` and `@EventPattern`?

`@MessagePattern` establishes a request-response relationship where the client awaits a reply (RPC), while `@EventPattern` implements fire-and-forget event distribution where the emitter does not expect a response. The `ListenersController` registers both types in [`packages/microservices/listeners-controller.ts`](https://github.com/nestjs/nest/blob/main/packages/microservices/listeners-controller.ts).

### How do I handle errors in microservice handlers?

Throw `RpcException` from your handler methods. The `ListenersController` catches exceptions and passes them through `ExceptionFiltersContext`, serializing the error for transport back to the client in a format consistent with NestJS's HTTP error handling.