Introduction: Why TypeScript in Microservices?
Microservice architecture has become the standard for building scalable and fault-tolerant applications. However, the choice of programming language can significantly impact development speed and code quality. TypeScript — a strictly typed superset of JavaScript — offers an ideal balance between flexibility and reliability. Thanks to static typing, interfaces, and a powerful module system, TypeScript allows you to catch errors at compile time rather than at runtime, which is critical for distributed systems.
In this article, we will break down the key principles of building microservices with TypeScript, explore popular frameworks (NestJS, Fastify), configure inter-service communication via RabbitMQ, and containerization with Docker. All code examples will be presented in TypeScript so you can immediately apply them in your projects.
1. Framework Choice: NestJS vs Fastify
There are several frameworks for creating microservices in TypeScript. The two most popular are NestJS and Fastify. Let's look at their features.
NestJS — "Angular for the backend"
NestJS offers a modular architecture inspired by Angular. It comes with a built-in transport layer for microservices (TCP, Redis, RabbitMQ, Kafka). This is an ideal choice for large projects where structure and team developer support are important.
// Example of a basic microservice in NestJSimport { NestFactory } from '@nestjs/core';import { Transport, MicroserviceOptions } 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: 'orders_queue', queueOptions: { durable: false }, }, }, ); await app.listen();}bootstrap();Fastify — Performance and Simplicity
Fastify is an ultra-fast HTTP framework for Node.js. It does not provide built-in microservice support but easily integrates with RabbitMQ or NATS through separate packages. It is suitable for cases where performance is critical and the architecture is already defined.
// Example of a Fastify + TypeScript serverimport fastify from 'fastify';
const server = fastify({ logger: true });
server.get('/health', async (request, reply) => { return { status: 'OK', service: 'payment-service' };});
const start = async () => { try { await server.listen({ port: 3000 }); } catch (err) { server.log.error(err); process.exit(1); }};start();Conclusion: For beginners and team projects, choose NestJS. For high-load systems with a well-thought-out architecture, choose Fastify.
2. Inter-service Communication: RabbitMQ and Redis
In a microservice architecture, services communicate with each other through message brokers or direct HTTP requests. Let's look at two popular approaches.
RabbitMQ — Reliable Message Queue
RabbitMQ provides asynchronous message delivery with delivery guarantees. In TypeScript, the amqplib library or NestJS built-in modules are often used to work with RabbitMQ.
// Publishing a message to RabbitMQ (TypeScript)import * as amqp from 'amqplib';
async function publishOrder(order: any) { const connection = await amqp.connect('amqp://localhost'); const channel = await connection.createChannel(); const queue = 'orders';
await channel.assertQueue(queue, { durable: true }); channel.sendToQueue(queue, Buffer.from(JSON.stringify(order)), { persistent: true, });
console.log(`Order sent: ${order.id}`); setTimeout(() => connection.close(), 500)