Building Microservices with NestJS: A Comprehensive Guide

@rnab
3 min readJan 4, 2025

--

In today’s rapidly evolving tech landscape, microservices architecture has emerged as a popular approach to designing scalable and resilient applications. This architecture allows you to break down a monolithic application into smaller, independently deployable services that work cohesively. One powerful framework that facilitates this approach in the Node.js ecosystem is NestJS.

In this article, we’ll delve into how to build microservices with NestJS, exploring essential concepts, features, and providing practical examples.

Why Choose NestJS for Microservices?

NestJS is a progressive Node.js framework built with TypeScript, designed to offer a mature and versatile development experience. Here are some reasons why NestJS stands out for microservices architecture:

  1. Modular Design: NestJS promotes a highly modular structure, making it easy to organize code and manage dependencies.
  2. Built-in Support: NestJS offers seamless support for microservices with pre-configured transport layers like TCP, gRPC, Redis, and NATS.
  3. TypeScript: Being built with TypeScript ensures type safety and robust code.

Setting Up Your Project

First, let’s start by setting up a new NestJS project. To scaffold a NestJS application, you need the Nest CLI installed:

npm i -g @nestjs/cli
nest new microservice-demo

Navigate to the newly created directory:

cd microservice-demo

Now you have a project set up with the basic scaffold provided by the Nest CLI.

Creating a Basic Microservice

Let’s create a basic microservice for user management. In a real-world scenario, this might involve operations such as user registration, authentication, and retrieval of user details.

  1. Generate a new module and service for users:
  • nest g module users nest g service users
  1. Inside the users.service.ts file, implement some basic logic:
  • import { Injectable } from '@nestjs/common'; @Injectable() export class UsersService { private readonly users = new Map<string, any>(); createUser(id: string, name: string) { this.users.set(id, { id, name }); } getUser(id: string) { return this.users.get(id); } }
  1. Now, let’s create a controller to handle incoming requests. Generate a controller and use the service in it:
  • nest g controller users
  1. Inside users.controller.ts, wire up the routes:
  • import { Controller, Get, Param, Post, Body } from '@nestjs/common'; import { UsersService } from './users.service'; @Controller('users') export class UsersController { constructor(private readonly usersService: UsersService) {} @Post() createUser(@Body() body: { id: string, name: string }) { this.usersService.createUser(body.id, body.name); } @Get(':id') getUser(@Param('id') id: string) { return this.usersService.getUser(id); } }

Microservice Communication

NestJS simplifies microservice communication using transporters. We’ll demonstrate communication using TCP transport.

Setting Up the Gateway Service

First, let’s create a gateway to handle communication between microservices.

  1. Generate a new NestJS application for the gateway:
  • nest new gateway
  1. Open main.ts of the gateway application and set up the microservice client:
  • import { NestFactory } from '@nestjs/core'; import { AppModule } from './app.module'; import { Transport } from '@nestjs/microservices'; async function bootstrap() { const app = await NestFactory.create(AppModule); app.connectMicroservice({ transport: Transport.TCP, options: { host: '127.0.0.1', port: 3001 }, }); await app.startAllMicroservicesAsync(); await app.listen(3000); } bootstrap();

Setting Up the User Microservice

  1. Open main.ts of the user microservice and configure it as a microservice application:
  • import { NestFactory } from '@nestjs/core'; import { AppModule } from './app.module'; import { Transport, MicroserviceOptions } from '@nestjs/microservices'; async function bootstrap() { const app = await NestFactory.createMicroservice<MicroserviceOptions>(AppModule, { transport: Transport.TCP, options: { host: '127.0.0.1', port: 3001 }, }); await app.listenAsync(); } bootstrap();

Implementing Microservice Messaging

Modify the user service to handle messages from the gateway.

  1. In users.service.ts, enable message patterns:
  • import { Injectable } from '@nestjs/common'; import { MessagePattern } from '@nestjs/microservices'; @Injectable() export class UsersService { private readonly users = new Map<string, any>(); @MessagePattern({ cmd: 'create_user' }) createUser(data: { id: string, name: string }) { this.users.set(data.id, { id: data.id, name: data.name }); return { status: 'success' }; } @MessagePattern({ cmd: 'get_user' }) getUser(id: string) { return this.users.get(id); } }
  1. In the gateway, send messages to the user microservice:
  • import { Controller, Get, Param, Post, Body } from '@nestjs/common'; import { ClientProxy, ClientProxyFactory, Transport } from '@nestjs/microservices'; @Controller('users') export class UsersController { private client: ClientProxy; constructor() { this.client = ClientProxyFactory.create({ transport: Transport.TCP, options: { host: '127.0.0.1', port: 3001 }, }); } @Post() async createUser(@Body() body: { id: string, name: string }) { return this.client.send({ cmd: 'create_user' }, body).toPromise(); } @Get(':id') async getUser(@Param('id') id: string) { return this.client.send({ cmd: 'get_user' }, id).toPromise(); } }

Conclusion

With NestJS, setting up a microservice architecture becomes straightforward and efficient. Its modular design and built-in support for microservices enable developers to build scalable and maintainable applications seamlessly. By following this guide, you can start building your own microservices-based systems with NestJS.

Feel free to explore more advanced topics like error handling, service discovery, and more transporters as you become comfortable with the basics. Happy coding!

--

--

@rnab
@rnab

Written by @rnab

Typescript, Devops, Kubernetes, AWS, AI/ML, Algo Trading

No responses yet