Step-by-Step Guide to Building a Backend with NestJS and MongoDB
NestJS is a progressive, TypeScript-based framework for building scalable and maintainable backend applications. Its modular architecture and built-in support for MongoDB make it a great choice for modern backend development.
In this guide, we’ll walk through the steps to set up a backend project using NestJS with MongoDB as the database.
Step 1: Prerequisites
Before starting, ensure you have the following installed:
- Node.js: Download and install the latest LTS version from nodejs.org.
- npm or pnpm: npm comes with Node.js, or you can install
pnpmglobally using:
npm install -g pnpm
3.MongoDB: Install MongoDB locally or use a cloud database like MongoDB Atlas. You can download MongoDB from mongodb.com.
Step 2: Create a New NestJS Project
Run the following command to create a new NestJS project:
pnpm create nest-app my-backend
or
npx @nestjs/cli new bvg-backend
Choose a package manager when prompted (select pnpm if you’re using it). Navigate into the project directory:
cd my-backend
Step 3: Install MongoDB Package
NestJS uses the @nestjs/mongoose package to work with MongoDB. Install the required dependencies:
pnpm add @nestjs/mongoose mongoose
For development purposes, you can also install the types for mongoose:
pnpm add -D @types/mongoose
Step 4: Configure MongoDB Connection
Open the app.module.ts file and configure the MongoDB connection using the MongooseModule.
Update your code like this:
import { Module } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';
@Module({
imports: [
MongooseModule.forRoot('mongodb://localhost:27017/my-database'), // Replace with your MongoDB URI
],
})
export class AppModule {}
If you’re using MongoDB Atlas, replace the URI with your connection string.
Step 5: Create a Module for Your Feature
NestJS encourages modular development. Let’s create a user module as an example:
pnpm nest generate module users
This will generate a new folder users with a users.module.ts file.
Step 6: Create a Schema for MongoDB
In the users folder, create a schemas directory and add a user.schema.ts file:
mkdir src/users/schemas touch src/users/schemas/user.schema.ts
Define your schema in user.schema.ts:
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
import { Document } from 'mongoose';
@Schema()
export class User extends Document {
@Prop({ required: true })
name: string;
@Prop({ required: true, unique: true })
email: string;
@Prop()
age: number;
}
export const UserSchema = SchemaFactory.createForClass(User);
Step 7: Create a Service and Controller
Generate a service and controller for the Users module:
pnpm nest generate service users pnpm nest generate controller users
Step 8: Register the Schema in the Module
Update users.module.ts to include the MongooseModule:
import { Module } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';
import { UsersService } from './users.service';
import { UsersController } from './users.controller';
import { User, UserSchema } from './schemas/user.schema';
@Module({
imports: [
MongooseModule.forFeature([{ name: User.name, schema: UserSchema }]),
],
controllers: [UsersController],
providers: [UsersService],
})
export class UsersModule {}
Step 9: Implement CRUD Operations
In the users.service.ts file:
Add methods to interact with MongoDB:
import { Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import { User } from './schemas/user.schema';
@Injectable()
export class UsersService {
constructor(@InjectModel(User.name) private userModel: Model<User>) {}
async create(createUserDto: any): Promise<User> {
const newUser = new this.userModel(createUserDto);
return newUser.save();
}
async findAll(): Promise<User[]> {
return this.userModel.find().exec();
}
async findOne(id: string): Promise<User> {
return this.userModel.findById(id).exec();
}
async update(id: string, updateUserDto: any): Promise<User> {
return this.userModel.findByIdAndUpdate(id, updateUserDto, { new: true }).exec();
}
async delete(id: string): Promise<User> {
return this.userModel.findByIdAndRemove(id).exec();
}
}
In the users.controller.ts file:
Connect the service methods to API routes:
import { Controller, Get, Post, Body, Param, Put, Delete } from '@nestjs/common';
import { UsersService } from './users.service';
@Controller('users')
export class UsersController {
constructor(private readonly usersService: UsersService) {}
@Post()
async create(@Body() createUserDto: any) {
return this.usersService.create(createUserDto);
}
@Get()
async findAll() {
return this.usersService.findAll();
}
@Get(':id')
async findOne(@Param('id') id: string) {
return this.usersService.findOne(id);
}
@Put(':id')
async update(@Param('id') id: string, @Body() updateUserDto: any) {
return this.usersService.update(id, updateUserDto);
}
@Delete(':id')
async delete(@Param('id') id: string) {
return this.usersService.delete(id);
}
}
Step 10: Test the Application
- Start the server:
pnpm run start:dev
- Use Postman, Insomnia, or cURL to test the endpoints:
POST /usersto create a user.GET /usersto retrieve all users.GET /users/:idto retrieve a specific user.PUT /users/:idto update a user.DELETE /users/:idto delete a user.
Step 11: Add Validation (Optional)
Install class-validator and class-transformer for validation:
pnpm add class-validator class-transformer
Use decorators in DTOs to validate incoming data. For example:
import { IsString, IsEmail, IsOptional } from 'class-validator';
export class CreateUserDto {
@IsString()
name: string;
@IsEmail()
email: string;
@IsOptional()
@IsString()
age?: number;
}
Conclusion
Congratulations! 🎉 You’ve successfully built a NestJS backend using MongoDB. This modular approach ensures your application is scalable and maintainable. From here, you can expand the project by adding authentication, middleware, and additional features.
