How to Build Scalable Microservices with NestJS and MongoDB
In today’s rapidly evolving tech landscape, building scalable applications that can handle increased loads without compromising performance is paramount. Microservices architecture has emerged as a powerful design pattern, allowing developers to create modular and independent services that can be deployed and scaled individually. When paired with powerful frameworks like NestJS and databases like MongoDB, building these services becomes not only efficient but also enjoyable. In this article, we’ll explore how to build scalable microservices using NestJS and MongoDB, walking through definitions, use cases, and actionable insights, complete with code examples.
What Are Microservices?
Microservices are an architectural style that structures an application as a collection of small, independently deployable services. Each service is designed to perform a specific business function and can be developed, deployed, and scaled independently of other services. This modularity helps to enhance maintainability and scalability.
Key Characteristics of Microservices:
- Independent Deployment: Each service can be deployed without affecting other services.
- Decentralized Data Management: Each service can manage its own database, making it easier to handle data storage and retrieval.
- Technology Agnostic: Different services can be built using different technologies, allowing teams to choose the best tools for the job.
- Resilience: Failures in one service do not necessarily bring down the entire application.
Why Use NestJS and MongoDB?
NestJS
NestJS is a progressive Node.js framework designed for building efficient, reliable, and scalable server-side applications. It leverages TypeScript and incorporates decorators and dependency injection, making it ideal for developing microservices.
MongoDB
MongoDB is a NoSQL database that stores data in a flexible, JSON-like format, making it perfect for applications that require scalability and high performance. Its document-based structure aligns well with microservices, allowing each service to have its own database schema.
Setting Up Your Environment
Before diving into code, ensure that you have the following installed:
- Node.js (version 12 or later)
- MongoDB (either locally or using MongoDB Atlas)
- NestJS CLI
Step 1: Install NestJS CLI
First, install the NestJS CLI globally on your machine:
npm i -g @nestjs/cli
Step 2: Create a New Project
Create a new NestJS project:
nest new microservice-example
Navigate to the project directory:
cd microservice-example
Step 3: Install Necessary Packages
You will need to install the MongoDB package and the Mongoose ORM for data modeling:
npm install @nestjs/mongoose mongoose
Creating a Sample Microservice
Now, let’s create a simple microservice that manages a collection of "users."
Step 4: Define the User Schema
Create a new folder called users
in the src
directory, and inside it, create a file called user.schema.ts
.
// src/users/user.schema.ts
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
import { Document } from 'mongoose';
export type UserDocument = User & Document;
@Schema()
export class User {
@Prop({ required: true })
name: string;
@Prop({ required: true, unique: true })
email: string;
@Prop()
password: string;
}
export const UserSchema = SchemaFactory.createForClass(User);
Step 5: Create the Users Module
Generate a users module and service:
nest generate module users
nest generate service users
Then, update the users.module.ts
to include Mongoose and the User schema:
// src/users/users.module.ts
import { Module } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';
import { UsersService } from './users.service';
import { User, UserSchema } from './user.schema';
@Module({
imports: [MongooseModule.forFeature([{ name: User.name, schema: UserSchema }])],
providers: [UsersService],
exports: [UsersService],
})
export class UsersModule {}
Step 6: Implementing the Users Service
Now, let’s implement the logic to create and retrieve users in users.service.ts
:
// src/users/users.service.ts
import { Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import { User, UserDocument } from './user.schema';
@Injectable()
export class UsersService {
constructor(@InjectModel(User.name) private userModel: Model<UserDocument>) {}
async create(createUserDto: { name: string; email: string; password: string }): Promise<User> {
const createdUser = new this.userModel(createUserDto);
return createdUser.save();
}
async findAll(): Promise<User[]> {
return this.userModel.find().exec();
}
}
Step 7: Setting Up the Controller
Now we need to add a controller to handle incoming requests. Generate a users controller:
nest generate controller users
In users.controller.ts
, implement the endpoints:
// src/users/users.controller.ts
import { Body, Controller, Get, Post } from '@nestjs/common';
import { UsersService } from './users.service';
@Controller('users')
export class UsersController {
constructor(private readonly usersService: UsersService) {}
@Post()
async create(@Body() createUserDto: { name: string; email: string; password: string }) {
return this.usersService.create(createUserDto);
}
@Get()
async findAll() {
return this.usersService.findAll();
}
}
Step 8: Connecting to MongoDB
In your main.ts
, connect to your MongoDB database:
// src/main.ts
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { Mongoose } from 'mongoose';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
// Connect to MongoDB
await Mongoose.connect('mongodb://localhost/nest', {
useNewUrlParser: true,
useUnifiedTopology: true,
});
await app.listen(3000);
}
bootstrap();
Conclusion
By following these steps, you have successfully set up a scalable microservice using NestJS and MongoDB. This architecture allows your application to grow seamlessly, as you can add new services or scale existing ones without major overhauls.
Additional Tips for Scalability:
- Load Balancing: Use a load balancer to distribute traffic among multiple instances of your microservices.
- Caching: Implement caching strategies (like Redis) to reduce database load.
- Service Discovery: Use tools like Consul or Eureka to manage service discovery in a microservices environment.
Building microservices with NestJS and MongoDB not only enhances scalability but also fosters a robust development environment that can adapt to changing business needs. Start coding today and watch your application thrive!