I'm currently learning Nest.JS framework and because I organized my notes very well I decided to share them in this NestJS tutorial post.
I'm planning to make a boilerplate app with throughout this Nest.JS tutorial. The app will cover a simple authentication.
In this part, I'm going to try to explain basics of Nest and its basic concepts.
Since understanding NestJS requires some software development concepts, I will try to explain those concepts also:
- Decorators
- Dependency Inversion Principle
- Dependency Injection
- Inversion of Control
Introduction
For the demonstration purposes, let's look some basics of NestJS. You don't need to do anything rightnow until the next sextion. (We are going to create a Nest.js project with the CLI in the next section)
A) TypeScript Configurations in NestJS
NestJS is heavily uses decorators which is a feature of TypeScript. Decorators allows us to write cleaner and understandable code. You can also read: Understanding JavaScript decorators
B) NestJS Components
NestJS | Description |
---|---|
Pipe | Data validation in requests |
Guard | User authentication |
Modules | Groups the code together. A module wraps the controller. |
Controller | Route the request to a specific function |
Service | Business logic |
Repository | Database access |
Filters | Handles errors that occur during request handling |
Interceptors | Adds extra logic to incoming requests or outcoming responses |
C) Creating a project with the CLI
Another way of starting a NestJS project is scaffolidng with the Nest CLI.
You can visit http://localhost:3000
on your browser. You'll see that our app is running.
D) Creating a project manually
When you create a new project from scratch you need to install the libraries below.
Let's look what are those for:
Package | Description |
---|---|
@nestjs/common | The functions, classes and other useful stuff except the core package. |
@nestjs/core | The core package of NestJS. |
@nestjs/platform-express | Express library for handling HTTP requests. You can also choose Fastify as well. |
reflect-metadata | It is for using decorators. |
typescript | The package is required for using the superset of JavaScript. It is required since we are going to write our app in TypeScript. |
E) The Basic App Structure
After installation, we will see the default file structure and simple explanations taken from the official document.
![[nestjs-default-file-structure.png]]
Filename | Description | |
---|---|---|
app.controller.ts | A basic controller with a single route. | |
app.controller.spec.ts | The unit tests for the controller. | |
app.module.ts | The root module of the application. | |
app.service.ts | A basic service with a single method. | |
main.ts | The entry file of the application which uses the core function NestFactory to create a Nest application instance. |
1) NestJS Tutorial
1) Platform/Server
Nest aims to be a platform-agnostic framework. It works with any NodeJS server. However, out-of-the-box, it supports Express and Fastify.
Those platform-specific configurations and the most general NestJS configurations can be done with the app's entry point.
Let's look main.ts
file which is the entry point of the app.

A Nest application can be created with the NestFactory
's create
method which returns an app object that fulfills the INestApplication interface.
Later on, we will use some of the methods of the returned app object such as GlobalGuards
, GlobalPipes
, GlobalInterceptors
, etc...
By default, NestJS uses Express as its default Node server. You can use Fastify with NestJS as well as other Node servers.

2) Modules in NestJS
In Nest.js, every app has at least one module. Modules encapsulate closely related code components together. It is strongly suggested to use modules for organizing your code. By doing that, you can easily scale your code.
A module is a class annotated with a @Module()
decorator. In other words, we use @Module()
decorator with an object, in order to make a class a module.

A) The Root module
When you create a Nest app with the CLI, the root module of your app will be in app.module.ts
file.

B) What is a decorator?
Decorator is a concept that related with Decorator pattern which is a design pattern in object-oriented programming.
Decorators are functions that let you attach new behaviors to objects by placing these objects inside a special wrapper.
Decorators are currently "stage 2 proposal" for JavaScript. However, TypeScript supports using decorators. You can use 5 types of decorators in TypeScript:
- Property Decorators
- Method Decorators
- Accessor Decorators
- Parameter Decorators and
- Class Decorators, like we use in modules.

A class decorator is applied to the constructor of a class. It can observe, modify or replace a class definition. Also, it should be noted that a class decorator can not be used in a TypeScript declaration file.
For the details, you can check Decorators in TypeScript
You can also read this excellent article: A complete guide to TypeScript Decorators
Let's back to the modules.
C) Properties of the Module object
I said that a module decorator takes a single object. The properties of the object describe the module.
Property | Description |
---|---|
providers | the providers that will be instantiated by the Nest injector and that may be shared at least across this module |
controllers | the set of controllers defined in this module which have to be instantiated |
imports | the list of imported modules that export the providers which are required in this module |
exports | the subset of providers that are provided by this module and should be available in other modules which import this module. You can use either the provider itself or just its token (provide value) |
D) Notes on Modules
Some important things about the modules in NestJS:
- Modules use singleton design pattern. Therefore we can share the instance of any service provider between modules.
- Every module is automatically a shared module. Once created it can be reused by any module.
- We need to import its module first when we need to use any provider.
- Any module imported to another module also can be exported from.
- Because providers aren't registered in global scope, importing a specific module many times can be tedious. You can go around this problem by adding
@Global
decorator to a module (except lazy-loaded modules).
E) Create a new module with the CLI
Let's create a new module that will be responsible for the users of our app. If your Nest.JS app is running, you can stop it by pressing CMD/CTRL + C
.
In your terminal, execute the commands below:
This will create users
folder under src
directory. Under this directory, you'll see users.module.ts
file.
The module file is empty now. Let's fill it with some code components.

3) Controllers in NestJS
I previously said that a controller is responsible for routing a request to a specific function. Controllers are connected our app through a module.
There is a better way to create controller and resources than what we will do. Since this is a tutorial about NestJS, I am going to do many tasks manually. Otherwise, you can quickly create a CRUD API.
A) Creating a controller
Let's create a controller.
When you execute the command above, two new files will be generated: users.controller.ts
and users.controller.spec.ts
. The latter one is for test purposes and thus we can skip it now.
B) Notes on controllers
Also, please check the users.module.ts
file. You can see that the new controller is automatically appended to its module.
There are some things to be highlighted:
- Don't add contoller suffix to your controller name. It will be automatically suffixed.
- Putting --flat flag generates the controller without creating an extra folder. If you need more organized directory which put controller in a folder, you can omit it.
- The controller is automatically appended to the module
- The text in the controller decorator, which is "users" in our case, prefixes the routes under the controller. In other words, all the routes under this controller will start with
users
such as/users/:id
.
C) Adding routes to the controller
We created a very basic controller.
We need to add routes with the corresponding HTTP request. We should specify HTTP requests with decorators. @Get()
, @Post()
, @Put()
@Delete()
, @Patch()
, @Options()
, @Head()
, @All()
.
Let's create a CRUD API.
Request | Function | Endpoint |
---|---|---|
GET | getAllUsers | "/users/" |
POST | createUser | "/users/" |
GET | getUser | "/users/:id" |
Patch | updateUser | "/users/:id" |
Delete | removeUser | "/users/:id" |
D) REST API Client
To check our routes, there are several ways. You can use your favorite REST API Client such as Postman, Insomnia, Paw. I'm planning to use Thunder Client throughout this post. It is an extension for VS Code. If you are a VS Coder, the chances are high that you like it.

For the detailed instructions, you can visit: NestJS Controllers - Routing.
Since a controller method will be responsible only for routing, we need to create a service that will handle the business logic of our app.
E) Request, Response, Status, Body, Query, and Parameters
To get HTTP request and response objects and their properties like body, query, parameters, you can use their decorators: @Req
,@Res
You should also import underlying server type library if you need to take the advantage. (See the details)
Decorator | Platform Object |
---|---|
@Request(), @Req() | req |
@Response(), @Res()* | res |
@Next() | next |
@Session() | req.session |
@Param(key?: string) | req.params / req.params[key] |
@Body(key?: string) | req.body / req.body[key] |
@Query(key?: string) | req.query / req.query[key] |
@Headers(name?: string) | req.headers / req.headers[name] |
@Ip() | req.ip |
@HostParam() | req.hosts |
There are also other method decorators for your usage.
Decorator | Description |
---|---|
@HttpCode(statusCode: number) | Returns HTTP status code you given |
@Redirect(url?: string, statusCode?: number) | Redirect a response to a given URL with a given HTTP code |
Dynamic Routes and Query Variables
In some cases, we will require dynamic routes, for instance, the getUser
route. You can obtain a dynamic id
value with a special parameter decorator @Param().
You can optionally pass the dynamic parameter name to get its dynamic value; otherwise, you will get an object.
It should be noted that if you don't decorate the method with a dynamic route (with a colon and a parameter name) like :id
you can't obtain the value.
The same workflow is also valid for query strings in your route, except we use the @Query()
decorator.
Let's change your controller's getUser
method by first importing Param
and Query
decorators from @nestjs/common
library.
After import, I'll assign route parameter to params
and query string to qs
by decorating them.
For demonstration purposes, I can send a get request to the route: http://localhost:3000/users/5?order=asc
.
You'll see the logs below on your termina:

It is better to demonstrate a PUT request. In order to that, send a PUT request to http://localhost:3000/users
with the JSON payload {"email":"example@example.com" }
.
I'll import Body
and Headers
decorator from @nestjs/common
and change createUser
method.

Since a controller method will be responsible only for routing, we need to create a service that will handle the business logic of our app. However, are we sure about the validity of requested data? Let's be sure about that.

4) Pipes (Data Validation )
Pipes in NestJS are for data validation in requests. They validate or transform the data before reaching the controller.
The two usecase of pipes are below.
- Data validation
- Data transformation

To use those functionalities, we need to install two extra packages in the next step. Those are:
- class-transformer: Decorator-based transformation, serialization, and deserialization between objects and classes.
- class-validator: Decorator-based property validation for classes.
NestJS provides eight pipes available out-of-the-box, you could also write your own. Those built-in pipes are: ValidationPipe
, ParseIntPipe
, ParseFloatPipe
, ParseBoolPipe
, ParseArrayPipe
, ParseUUIDPipe
, ParseEnumPipe
, DefaultValuePipe
. You can read the details: NestJS Pipe
Now, there are a couple of things to do for setting automatic validation.
- We will register the validation globally;
- We should define the expected data, which we will call "data transfer object."
- We should define validation rules and apply all of them to a request handler.
A) Registering a Global Pipe
To use the ValidationPipe, we need to tell NestJS to use this validation globally. In other words, we need to set up automatic validation globally. After registering the ValidationPipe globally, we will define different rules for different routes.
Open and edit the main.ts
file accordingly.
B) Data Transfer Object - dto
The next step is creating a class that describes the rules the request body must-have. This class is referred to as Data Transfer Object,
generally abbreviated as dto.
We will create a file that includes a class that describes all the different properties we expect our post request handler to receive.
We've created three different dto files. Now, we will define those files and ensure the requested data is valid.
We decorate dto objects with the decorators imported from class-validator
.
The validation classes are ready. When we put those as a type annotation of any request, they will validate incoming requests.
Let's try them. You can update users.controller.ts
file according to this:
It is time to test it. I am going to send a post request to createUser
route with a missing password
property.
The result will be as expected.
I think this is enough for the first post of Nest.JS tutorial. I'm planning to cover providers and interceptors in the next post. Thanks for reading.