Back to all posts

Building a Scalable Microservices Architecture with NestJS & RabbitMQ

S
sonhp
β€’
10 min read

Building a Scalable Microservices Architecture with NestJS & RabbitMQ

As applications grow, monolithic architectures often become bottlenecks. Microservices allow us to break down applications into smaller, independently deployable services. In this post, we’ll build a scalable microservices system in NestJS using RabbitMQ for asynchronous communication.


1. Why Microservices?

πŸ”Ή Scalability – Services can scale independently.
πŸ”Ή Fault Isolation – Failure in one service doesn’t bring down the entire app.
πŸ”Ή Technology Flexibility – Different services can use different tech stacks.

However, microservices also introduce complexity:
❌ Distributed Data Management
❌ Network Overhead
❌ Inter-Service Communication

To manage communication, we’ll use RabbitMQ, a message broker for handling async messaging.


2. Setting Up a NestJS Microservice with RabbitMQ

Installing Dependencies

First, install RabbitMQ-related packages:

npm install @nestjs/microservices amqplib

Start a RabbitMQ instance using Docker:

docker run -d --name rabbitmq -p 5672:5672 -p 15672:15672 rabbitmq:management

πŸ”Ή RabbitMQ UI: http://localhost:15672 (User: guest, Password: guest)
πŸ”Ή Message Broker Port: 5672


3. Creating a Microservice in NestJS

Defining the Microservice Module

In a microservices architecture, services operate independently. Here’s an example Order Service that listens for messages from other services.

import { Module } from '@nestjs/common';
import { OrdersService } from './orders.service';
import { OrdersController } from './orders.controller';

@Module({
  providers: [OrdersService],
  controllers: [OrdersController],
})
export class OrdersModule {}

4. Setting Up RabbitMQ Transport in NestJS

NestJS provides a built-in microservices transport layer to work with message brokers. Modify main.ts to initialize RabbitMQ transport:

import { NestFactory } from '@nestjs/core';
import { MicroserviceOptions, Transport } from '@nestjs/microservices';
import { OrdersModule } from './orders/orders.module';

async function bootstrap() {
  const app = await NestFactory.createMicroservice<MicroserviceOptions>(
    OrdersModule,
    {
      transport: Transport.RMQ,
      options: {
        urls: ['amqp://localhost:5672'],
        queue: 'orders_queue',
        queueOptions: { durable: false },
      },
    },
  );

  await app.listen();
  console.log('Orders Microservice is running...');
}
bootstrap();

5. Handling Incoming Messages

Define an event handler for messages sent to orders_queue:

import { Controller } from '@nestjs/common';
import { MessagePattern } from '@nestjs/microservices';
import { OrdersService } from './orders.service';

@Controller()
export class OrdersController {
  constructor(private readonly ordersService: OrdersService) {}

  @MessagePattern('create_order')
  handleOrderCreation(data: any) {
    return this.ordersService.createOrder(data);
  }
}

πŸ”Ή MessagePattern('create_order') – Listens for messages sent with the topic create_order.


6. Sending Messages from Another Microservice

Now, let's assume we have a Payment Service that notifies the Order Service when a payment is processed.

Modify PaymentService to send a message:

import { Injectable } from '@nestjs/common';
import {
  ClientProxy,
  ClientProxyFactory,
  Transport,
} from '@nestjs/microservices';

@Injectable()
export class PaymentService {
  private client: ClientProxy;

  constructor() {
    this.client = ClientProxyFactory.create({
      transport: Transport.RMQ,
      options: {
        urls: ['amqp://localhost:5672'],
        queue: 'orders_queue',
        queueOptions: { durable: false },
      },
    });
  }

  async notifyOrderService(orderData: any) {
    return this.client.emit('create_order', orderData);
  }
}

πŸ”Ή emit('create_order', orderData) – Sends an async message to orders_queue.
πŸ”Ή ClientProxyFactory – Used to create a message broker client.


7. Handling Asynchronous Responses

Instead of just sending messages, sometimes we need a response. Modify OrdersController to return data when a request is received:

@MessagePattern('get_order')
getOrder(data: { orderId: string }) {
  return this.ordersService.findOrderById(data.orderId);
}

Now, the Payment Service can request order details like this:

const orderDetails = await this.client
  .send('get_order', { orderId: '1234' })
  .toPromise();
console.log(orderDetails);

πŸ”Ή send() – Unlike emit(), it expects a response from the receiving service.


8. Scaling Microservices with Multiple Instances

Since microservices run independently, we can scale them horizontally.

To start multiple instances of a service, run:

npm run start:dev # Instance 1
PORT=4001 npm run start:dev # Instance 2
PORT=4002 npm run start:dev # Instance 3

RabbitMQ will automatically distribute messages among available instances!


9. Securing RabbitMQ Communication

To improve security:

βœ… Use Authentication – Set up username/password for RabbitMQ.
βœ… Enable SSL/TLS – Encrypt messages between services.
βœ… Use Dead Letter Queues (DLQ) – Prevent message loss.

To enable RabbitMQ authentication, modify docker run:

docker run -d --name rabbitmq -p 5672:5672 -p 15672:15672 -e RABBITMQ_DEFAULT_USER=user -e RABBITMQ_DEFAULT_PASS=securepass rabbitmq:management

And update NestJS connection:

urls: ['amqp://user:securepass@localhost:5672'];

10. Monitoring Microservices in Production

For observability, integrate:

βœ… Prometheus & Grafana – Monitor service performance.
βœ… Jaeger – Distributed tracing to track requests across microservices.
βœ… RabbitMQ Management Plugin – Monitor queues and messages.

To enable RabbitMQ monitoring, visit:
πŸ”— http://localhost:15672


Conclusion

πŸ”Ή Microservices + RabbitMQ enable scalable and efficient communication.
πŸ”Ή Message brokers ensure decoupled and resilient services.
πŸ”Ή NestJS Microservices Module simplifies RabbitMQ integration.

By implementing asynchronous communication, we achieve better scalability, fault tolerance, and improved service reliability.

S

Written by sonhp

Technical writer and developer passionate about web technologies.

Related Articles