In modern web development, backend frameworks have evolved significantly, offering more structured, scalable, and efficient ways to build applications. One such framework that has gained popularity in the Node.js ecosystem is NestJS. It’s a powerful, opinionated framework built with TypeScript, inspired by Angular, which offers developers a robust architecture for building scalable server-side applications.
In this blog post, we will walk you through the steps of setting up a backend project using NestJS, from installation to creating basic modules, controllers, and services. Whether you’re a seasoned developer or a beginner, this guide will provide you with a solid foundation for getting started with NestJS.
1. Prerequisites
Before diving into NestJS, make sure you have the following installed:
- Node.js: NestJS is built on top of Node.js, so you’ll need it installed on your machine.
- npm (or yarn): Node’s package manager to manage dependencies.
You can download Node.js from the official website.
Check if you have npm installed:
bashCopyEditnpm -v
If you’re planning to use Yarn, install it via:
bashCopyEditnpm install --global yarn
2. Installing NestJS CLI
NestJS provides a Command Line Interface (CLI) tool that simplifies the process of scaffolding and managing your project. To install it globally, use the following command:
bashCopyEditnpm install -g @nestjs/cli
Alternatively, if you’re using Yarn:
bashCopyEdityarn global add @nestjs/cli
3. Creating a New NestJS Project
Once the NestJS CLI is installed, you can create a new project by running:
bashCopyEditnest new project-name
This will prompt you to choose the package manager (npm or yarn). After you select your preferred option, the CLI will generate a new NestJS project with a basic folder structure.
Project Structure:
- src/: Contains the main application files.
- app.controller.ts: Handles incoming requests and routes them to appropriate handlers.
- app.module.ts: Defines the root module of the application.
- app.service.ts: Contains the business logic of your app.
- node_modules/: Contains the dependencies.
- package.json: Manages project dependencies and scripts.
4. Running the Development Server
To start the development server and run the application, use the following command:
bashCopyEditnpm run start:dev
This will start the server on port 3000
by default. You can now open your browser and go to http://localhost:3000
to see your NestJS application running.
5. Creating Modules, Controllers, and Services
NestJS follows a modular architecture, which makes it easy to manage your application’s code and scale it over time. You’ll typically break your application into smaller modules, each with its own controller, service, and other components.
Creating a Module
Modules help organize your code into logical units. To create a new module, run:
bashCopyEditnest generate module users
This will create a users
folder inside the src/
directory, containing a module file named users.module.ts
.
Creating a Controller
Controllers in NestJS handle HTTP requests and return responses. To create a controller for the users
module, run:
bashCopyEditnest generate controller users
This generates a users.controller.ts
file. Inside this file, you will define methods that handle HTTP requests (e.g., GET
, POST
, PUT
, DELETE
).
typescriptCopyEditimport { Controller, Get } from '@nestjs/common';
@Controller('users')
export class UsersController {
@Get()
findAll(): string {
return 'This action returns all users';
}
}
Creating a Service
Services contain the business logic and are typically injected into controllers. To generate a service for the users
module, run:
bashCopyEditnest generate service users
This creates a users.service.ts
file. In the service, you can define methods to retrieve data, perform business logic, etc.
typescriptCopyEditimport { Injectable } from '@nestjs/common';
@Injectable()
export class UsersService {
findAll(): string {
return 'This action returns all users from the database';
}
}
Connecting the Controller and Service
To connect the controller and service, you will need to inject the service into the controller and call the service methods.
In users.controller.ts
:
typescriptCopyEditimport { Controller, Get } from '@nestjs/common';
import { UsersService } from './users.service';
@Controller('users')
export class UsersController {
constructor(private readonly usersService: UsersService) {}
@Get()
findAll(): string {
return this.usersService.findAll();
}
}
6. Using DTOs (Data Transfer Objects)
In NestJS, DTOs are used to define the structure of data that will be passed through the application. These are particularly useful when handling incoming request data, such as when creating or updating users.
To create a simple DTO for a User
, first, create a create-user.dto.ts
file in the users
module:
typescriptCopyEditexport class CreateUserDto {
readonly name: string;
readonly email: string;
}
Then, in the controller, use the @Body()
decorator to automatically validate and transform incoming request data:
typescriptCopyEditimport { Controller, Post, Body } from '@nestjs/common';
import { CreateUserDto } from './dto/create-user.dto';
@Controller('users')
export class UsersController {
@Post()
create(@Body() createUserDto: CreateUserDto): string {
return `User ${createUserDto.name} created successfully!`;
}
}
7. Using Middleware
NestJS supports middleware, which can run before your route handler, allowing you to perform tasks such as logging, authentication, or validation.
To create a middleware, first create a file in the users
module:
typescriptCopyEditimport { Injectable, NestMiddleware } from '@nestjs/common';
import { Request, Response, NextFunction } from 'express';
@Injectable()
export class LoggerMiddleware implements NestMiddleware {
use(req: Request, res: Response, next: NextFunction) {
console.log('Request made at: ', Date.now());
next();
}
}
Then, register it in your module’s configure()
method:
typescriptCopyEditimport { MiddlewareConsumer, Module, NestModule } from '@nestjs/common';
import { UsersController } from './users.controller';
import { UsersService } from './users.service';
import { LoggerMiddleware } from './middlewares/logger.middleware';
@Module({
controllers: [UsersController],
providers: [UsersService],
})
export class UsersModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer.apply(LoggerMiddleware).forRoutes(UsersController);
}
}
8. Connecting to a Database (Optional)
NestJS supports various database options such as TypeORM, Sequelize, and Mongoose. To set up a database connection, you can install an ORM (like TypeORM) and configure it in your application.
For example, to use TypeORM, install the required dependencies:
bashCopyEditnpm install --save @nestjs/typeorm typeorm mysql2
Then, configure TypeORM in the app.module.ts
:
typescriptCopyEditimport { TypeOrmModule } from '@nestjs/typeorm';
@Module({
imports: [
TypeOrmModule.forRoot({
type: 'mysql',
host: 'localhost',
port: 3306,
username: 'root',
password: 'password',
database: 'nestjs_db',
entities: [],
synchronize: true,
}),
],
})
export class AppModule {}
9. Conclusion
Setting up a backend project using NestJS is straightforward, thanks to its powerful CLI and modular structure. It provides a scalable solution for building everything from small APIs to large enterprise-level applications.
In this blog, we’ve covered the basics of creating a NestJS project, including generating modules, controllers, and services, working with DTOs and middleware, and connecting to a database. NestJS’s rich features, such as support for TypeScript, dependency injection, and modular design, make it a great choice for building maintainable and scalable applications.
Start experimenting with NestJS in your next backend project and see how it helps streamline your development process.