Microservices in TypeScript: Architecture and Practice

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Introduction: Why TypeScript is Ideal for Microservices

Microservice architecture has become the standard for building complex, scalable, and fault-tolerant applications. TypeScript, thanks to its strict typing, rich ecosystem, and support for asynchrony, is one of the best languages for implementing microservices. It allows you to write code that is easier to refactor, test, and document, which is critically important when splitting a system into dozens of independent services.

In this article, we will analyze architectural principles, build a simple microservice on NestJS, configure inter-service communication via RabbitMQ, and package everything in Docker Compose. You will get a ready-made practical foundation to start with.



Microservice Architecture in TypeScript

Proper architecture is the key to success. For TypeScript microservices, three key layers are distinguished:

  • Transport Layer — responsible for receiving and sending requests (HTTP, gRPC, message queues).
  • Business Logic — pure functions and services independent of the framework.
  • Data Layer — repositories and ORMs (TypeORM, Prisma).

Each microservice should be autonomous: have its own database, CI/CD, and deployment logic. Communication between services is usually implemented via asynchronous queues (RabbitMQ, Kafka) or synchronous calls (gRPC).



Practice: Creating a Microservice on NestJS



Step 1: Project Initialization

Install the NestJS CLI and create a new project:

npm i -g @nestjs/clinest new user-service --package-manager npmcd user-service


Step 2: Adding Microservice Support

NestJS has built-in support for microservice transporters. Let's install RabbitMQ:

npm install @nestjs/microservices amqplib amqp-connection-manager

Let's create main.ts that runs the service as a microservice:

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

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


Step 3: Implementing the Controller

Let's create a simple controller that processes messages from the queue:

import { Controller } from '@nestjs/common';import { MessagePattern, Payload } from '@nestjs/microservices';

@Controller()export class UserController { @MessagePattern('user.create') createUser(@Payload() data: { name: string; email: string }): string { // Business logic for creating a user should go here return `User ${data.name} created`; }}

Now any service can send a message to the user_queue with the pattern user.create and receive a response.



Inter-Service Communication: Synchronous and Asynchronous



Synchronous: gRPC

For high-load systems requiring strict typing and low latency, use gRPC. Install the package:

npm install @nestjs/microservices @grpc/grpc-js @grpc/proto-loader

Define a .proto file:

syntax = "proto3";package user;service UserService {  rpc GetUser (UserId) returns (User);}message UserId { int32 id = 1; }message User { string name = 1; string email = 2; }

In the controller, use the @GrpcMethod decorator to handle the request.



Asynchronous: RabbitMQ

Blogs

Book Recommendations