NestJS Typescript: The Ultimate Guide (2023)

NestJS is one of the fastest-growing typescript frameworks in the Node.js ecosystem. You will learn Nest.js from scratch to an advanced level using TypeScript.

NestJS Typescript: The Ultimate Guide (2023)

Chapter 1: Complete NestJS Overview

This guide will learn a fascinating framework in the Node.js and TypeScript ecosystem.

Prerequisites

Before continuing with this guide, you will need to understand what server-side web programming, frameworks, general Knowledge of JavaScript, TypeScript, and NodeJS are, which will aid your understanding of the NestJS framework.

Typescript: The Complete Developer’s Guide is my all-time TypeScript best course. You will master Typescript by learning popular design patterns and building complex projects with it. Includes React and Express!

You will learn the Nestjs typescript framework from scratch to an advanced level and how to install Node.js and set up the NestJS server on your local machine.

Also, you will learn how to connect a MongoDB database with NestJS and build and deploy a full-blown application to the server.

Let’s dive right in:

What is NestJS?

NestJS has proven to be the fastest-growing TypeScript framework for building flexible, scalable, large-scale, and enterprise-ready backend applications using Node.js. 

When building highly testable, well-structured, and maintainable backend applications using TypeScript, NestJS is the top choice for top organizations.

NestJS has over 39,000 GitHub Stars and 3,900 Forks on GitHub at the time of writing.

A weekly download of up to 700,000 over the last 6-months from NPMTrends makes Nest.js framework a goto framework for crafting out your backend project with Node.js and TypeScript.

As a complete web framework with high structure and well-structured architectures, the NestJS typescript framework has great features that make it scalable, testable, and maintainable.

Let’s dive into them:

Features of NestJS

TypeScript

NestJs is built with TypeScript, and it’s the most popular in this ecosystem. 

This integration drastically reduces the errors involved with Type-checking and Type inconsistencies when using JavaScript to build large-scale and enterprise applications.

CLI

NestJS provides the most powerful CLI tool. The tool can create and manage any part of the NestJS framework by typing in your terminal commands. 

The CLI is a single point of truth for command freaks to develop applications with NestJS without much of the GUI interactions.

With the CLI, you can create databases to create modules, controllers, and services files by typing in a few commands.

Documentation

NestJS provides very clean and well-documented guides for beginners to build simple to complex applications with the NestJS typescript framework.  

With the documentation, it’s straightforward to get started, and almost all your development questions have already been covered in the documentation.

Microservices

Aside from the traditional architectural style of development called Monolithic.

NestJS natively supports the microservice architectural development style right out of the box by providing proper integration to many popular microservice tools such as Kafka, gPRC, RabbitMQ, etc.

Popular Libraries

NestJS supports different popular tools out of the box, which lessens development hassles and increases faster application development. The best developer tools are already integrated, following best practices and industry standards.

NestJS supports TypeORM, Mongoose, GraphQL, Logging, Validation, Caching, WebSockets, and much more right out of the box, and no extra configuration is needed.

Aside from these general features of NestJS, many great features come with using NestJS for your project that we didn’t list out.

Why you should learn NestJS

Doubting a new framework happens to everyone first. At least it happens to me.

It is most appropriate to say, is it not another Node.js framework?

Why should I bother learning it?

Here is why?

Firstly different reasons propel a company or individual to choose a particular framework for their project.

We will explore the benefits of using the Nest.js framework for your project over other Node.js frameworks based on our personal experience with NestJS and compare NestJS to other frameworks to help you solidify your decision.

First, NestJS follows and improves upon the standards and structures used by the popular Front-end framework called Angular. So if you’re coming from Angular to NestJS, then you can likely get started with it in a day.

Next, the Nest.js team focuses on building great architectural structures for enterprise applications right out of the box.

This feature makes it easy for developers to build highly scalable and maintainable enterprise applications faster.

If the above benefits are not enough, here are our top benefits for switching to NestJS:

  • Building scalable and maintainable enterprise-ready applications is a breeze because it uses modern technologies such as TypeScript, bullet-proof architectural patterns.

  • It also supports many popular enterprise tools right out of the box such as GraphQL, WebSockets, Kafka, RabbitMQ for building large microservice applications.

  • NestJS framework also support tools such as TypeORM, Mongoose, Logging, Validation, Caching, WebSockets, and much more right out of the box and no extra configuration is needed.

NestJS Framework vs Other Frameworks

Comparing the top 5 TypeScript framework with NestJS shows that NestJS is one of the top Node.js frameworks except ExpressJS and KoaJS, which has been around for quite a while and still use JavaScript.

NestJS has more than 39,000 Github Stars and about 84,137 Github Usage as of the time of writing.

It has records of 747,391 Downloads in the last one month from Jul. 25, 2021, below, and above all, it supports TypeScript as a first-class citizen with about 99.8% Typescript in its codebase.

A picture speaks a thousand more than text. Let’s visually compare NestJS:

aRMHwXei.png

NestJS stats from Npmtrends

You can explore a complete comparison of Nest.js with other Node.js TypeScript frameworks for a more exquisite comparison.

Now you have a complete overview of the Nest.js Framework, Let’s dive right into the framework itself.

Now you have a complete overview of the Nest.js Framework, Let’s dive right into the framework itself.

Before you dive in, I will personally recommend you check out Nest.js: The Complete Developer’s Guide course. I learned how to build full-featured backend APIs incredibly quickly with Nest, TypeORM, and Typescript, including testing and deployment!

Chapter 2: NestJS The Framework

In this chapter, the tutorial will explore a little about the NestJS framework.

We will discuss the structure of the framework and how it combines the elements of OOP (Object Oriented Programming), FP (Functional Programming), and FRP (Functional Reactive Programming) in this tutorial.

This tutorial will discuss the most important problem that NestJS solves in the backend web development ecosystem → Architecture.

Finally, we will discuss how NestJS uses Angular architectural structure to solve the architectural problem of backend development to build highly testable, scalable, and maintainable applications.

You should note that the NestJS framework uses ExpressJS under the hood, and with the ultimate guide to Express, you will learn ExpressJS from the beginner's level to build your first real-world project with ExpressJS.

If you’re excited as we are, let’s dive right in.

As you may have noticed already, NestJS strongly follows the OOP, FP, and FRP architectural patterns.

Let’s explore each of these concepts:

What is OOP?

Object-Oriented Programming (OOP) is a paradigm that organizes software design around data and objects rather than functions and logic.

In OOP, everything is an object and can relate to another object to perform different functions either in a group or individually.

What is FP?

Functional Programming(FP) is also a programming paradigm where programs are constructed by applying and composing functions.

When a pure function is called with arguments, it will always return the same result.

What is FRP?

Functional Reactive Programming (FRP) is a programming model for reactive programming (Asynchronous Dataflow Programming) using the building blocks of functional programming.

This content will give you a clearer overview of FP, RP, and FRP to foster your understanding of the NestJS framework.

These different paradigms and models’ combination allows developers and teams to create highly testable, scalable, loosely coupled, and easily maintainable applications and architecture the angular heavily inspires.

Nest.js Architecture

Nest.js uses a 3-tier architecture that separates codes into 3 main components and enables developers to create fewer spaghetti codes:

  1. Controllers

  2. Services

  3. Data Access layer

nestjs_architecture.png

Nest.js 3rd-tier layer architecture

Controllers

They serve as a middleman between client requests and responses. It is responsible for handling the incoming requests and returning responses to the client through HTTP protocol.

controller.png

Overview of Nest.js controllers

The controller receives a specific request for the application through the routing mechanism created and processes the request.

Nest.js uses classes and decorators to create controllers and map each class method to routes to receive a specific request.

Here is an example of a controller using decorators:

import { Controller, Get } from '@nestjs/common';

@Controller('todos')
export class TodosController {
  @Get()
  findAll(): string {
    return 'This action returns all todos';
  }
}

The @Controllers, and @Get are the decorators used to inform Nest.js that we are creating a Todos controller and the findAll method is a GET request.

Services

Services are part of Nest.js Providers. Providers are the fundamental of Nest.js, with the main idea of injecting it as a dependency.

With dependency injection, relationships among various components, controllers, and other application parts are created.

Specifically, services are part of the code block that includes only the business logic.

For example, implementing all the database CRUD operations and methods to determine how data can be created, stored, and updated.

Here is an example of Services used to manage an array of Todos:


import { Injectable } from '@nestjs/common';
import { Todo } from './interfaces/todo.interface';

@Injectable()
export class CatsService {
  private readonly todos: Todo[] = [];

  create(todo: Todo) {
    this.todos.push(todo);
  }

  findAll(): Todo[] {
    return this.todos;
  }
}

The service class uses the Injectable() decorator showing that it is a provider and it can be injected as a dependency into any other class. e.g., controllers.

Next, we created a todos array that will contain all our todos that will be created using the create method and retrieved using the findAll method.

Data Access Layer

The data access layer takes care of and provides logic to access data stored in persistent storage of some kind.

It is located on the lowest level, dealing with the database and encapsulating data access details, and providing a friendly access interface for the upper layer.

Here is an example of an Entity-centric definition type:

interface Todo {
  title: string;
  description: string;
  isDone: boolean;
}

The code above shows a basic type definition for our Todo data. Now this interface can be customized to represent the different database schemas and columns that our application will use.

Directory Structures

In the initial stage of every project, defining a project structure is one of the important steps as it stands as a guide throughout the entire project.

Nest.js is important to have a project with a well-structured directory file to be much more readable, understandable, and easy to work with new and old team members to understand.

Below is the initial project structure of Nest.js after installation:

--src
  --app.controller.spec.ts
  --app.controller.ts
  --app.module.ts
  --app.service.ts
  --main.ts

The app.controller.ts and app.controller.spec.ts files contain basic controller logic for a single route and the controller’s unit tests, respectively.

Next, the app.module.ts is the root module of the application and app.service.ts is the service/data model logic of the application.

Lastly, the main.ts is the entry file of the application which uses the core function NestFactory to create a Nest application instance.

This simple directory structure can be expanded into a complete project by creating folders and arranging them based on their features.

Let’s take a look at creating a simple Todo application with an authentication directory structure:

--src
  ---auth
      --DTO
      --auth.controller.ts
      --auth.controller.spec.ts
      --auth.service.ts
      --auth.module.ts
      --auth.*.ts
  ---config
    --typeorm.config.ts
  ---todos
      --DTO
      --pipes
      --todos.controller.ts
      --todos.controller.spec.ts
      --todos.service.ts
      --todos.module.ts
      --todos.*.ts
  ---app.module.ts
  ---main.ts

As seen above, different files and folders could be created as the project grows in size and features.

For a holistic overview of Nest.js directory structure, check out this article Best Way to Structure Your Directory/Code (NestJS), by Prateek Kathal.

Now that we understand the inner workings of the Nest.js framework, let’s start building our first project following the structure:

Chapter 3: Building with NestJS

What better way to learn than understanding the theoretical and practical part of a technical topic.

So far, we have learned and gained more theoretical insights.

Let’s apply our knowledge practical to build a Todo application with Nestjs typescript framework.

This Nest.js tutorial will demonstrate how to use Nest.js to create a simple Todo application. With this, we will explore how to set up Nest.js with TypeScript.

Let’s dive right in:

Setting up Nest.js

You need to have Node.js and NPM installed on your local machi if you’re starting. To get started, download and install the latest Node.js with NPM.

Nest.js has evolved a lot over the years, with different versions and releases coming with different changelog, but in this tutorial, we will be using the current version 8 as of the time of writing.

To create our first project using Nest.js, we will follow the conventional way from the official documentation.

npm i -g @nestjs/cli
nest new nest-todo-app

The script above installs Nest.js CLI globally and uses the nest command to create a new project with the name nest-todo-app respectively.

Next, the script will ask you to select your favorite package manager, we will select npm and watch the command set up everything smoothly.

Lastly, open the folder in your favorite text editor and run the following command to build and serve the project for development.

npm run start:dev

You can delete all the app.**.ts TypeScript files except for the app.module.ts file to keep things clean.

Creating Controllers

We have already discussed above that controllers in Nest.js are meant to receive incoming HTTP requests from an application frontend and return an appropriate response. 

We can leverage the nest command to create, generate and modify Nest.js controllers, which can also help us generate some boilerplate codes.

Type this command in your project root terminal:

nest generate controller todo

The command will create two files, namely todo.controller.spec.ts and todo.controller.ts.

The first is used to write unit tests and should be ignored since it’s not the scope of this tutorial.

The next one is a TypeScript file decorated with the @Controller annotation.

Now, open the todo.controller.ts file and update its content with the following:

// /nest-todo-app/src/todo/todo.controller.ts
import {
  Controller,
  Get,
  Res,
  HttpStatus,
  Param,
  NotFoundException,
  Body,
  Put,
  Query,
  Delete,
  Post,
} from '@nestjs/common';
import { TodoService } from './todo.service';
import { CreateTodoDTO } from './dto/create-todo.dto';
@Controller('todos')
export class TodoController {
  constructor(private todoService: TodoService) {}

  // Create a todo
  @Post('/')
  async create(@Res() res, @Body() createTodoDTO: CreateTodoDTO) {
    const newTodo = await this.todoService.addTodo(createTodoDTO);
    return res.status(HttpStatus.OK).json({
      message: 'Todo has been submitted successfully!',
      todo: newTodo,
    });
  }

  // Fetch a particular todo using ID
  @Get('/:todoID')
  async getTodo(@Res() res, @Param('todoID') todoID) {
    const todo = await this.todoService.getTodo(todoID);
    if (!todo) {
      throw new NotFoundException('Todo does not exist!');
    }
    return res.status(HttpStatus.OK).json(todo);
  }

  // Fetch all todos
  @Get('/')
  async getTodos(@Res() res) {
    const todos = await this.todoService.getTodos();
    return res.status(HttpStatus.OK).json(todos);
  }

  // Edit a particular todo using ID
  @Put('/')
  async editTodo(
    @Res() res,
    @Query('todoID') todoID,
    @Body() createTodoDTO: CreateTodoDTO,
  ) {
    const editedTodo = await this.todoService.editTodo(todoID, createTodoDTO);
    if (!editedTodo) {
      throw new NotFoundException('Todo does not exist!');
    }
    return res.status(HttpStatus.OK).json({
      message: 'Todo has been successfully updated',
      todo: editedTodo,
    });
  }

  // Delete a todo using ID
  @Delete('/delete')
  async deleteTodo(@Res() res, @Query('todoID') todoID) {
    const deletedTodo = await this.todoService.deleteTodo(todoID);
    if (!deletedTodo) {
      throw new NotFoundException('Todo does not exist!');
    }
    return res.status(HttpStatus.OK).json({
      message: 'Todo has been deleted!',
      todo: deletedTodo,
    });
  }
}

The controller implements a simple CRUD business logic for our Todo application.

We have the create method which implements the Post method for creating a new Todo.

Next, we have the getTodo and getTodos which implements the Get method for retrieving all and single Todo, respectively.

Next, we have editTodo method which implements the Put method to update or edit the Todo that was already created.

Lastly, we have the deleteTodo method which implements the Delete method and allows us to delete our Todo.

Most importantly, every operation is performed inside the service class, which helps us separate business logic from actual data manipulation.

Creating Services

Services in Nest.js handle any complex business logic data manipulations for a specific purpose and return the appropriate response to the controller.

Run the following command in your project directory to generate a new service file:

nest generate service todo

Open the file and add the following codes:

// /nest-todo-app/src/todo/todo.service.ts

import { Injectable } from '@nestjs/common';
import { CreateTodoDTO } from './dto/create-todo.dto';

// Creates a Todo interface to show exactly the attribute of our Todo
interface Todo {
  readonly id: number;
  readonly title: string;
  readonly description: string;
  readonly isDone: boolean;
}

@Injectable()
export class TodoService {

// Creates a Todo array with one Todo
  private todos: Todo[] = [
    {
      id: 1,
      title: 'Test',
      description: 'This is a test Tod',
      isDone: true,
    },
  ];

// Creates a new todo (Add todo to array)
  async addTodo(createTodoDTO: CreateTodoDTO): Promise<Todo> {
    this.todos.push(createTodoDTO);

// return last added item
    return this.todos.at(-1);
  }

// Returns a single todo with ID
  async getTodo(todoID: number): Promise<Todo> {
    const post = this.todos.find((todo) => todo.id === todoID);
    return post;
  }

// Returns all todos available
  async getTodos(): Promise<Todo[]> {
    return this.todos;
  }

// Deletes a todo by ID and add a new one (Update process)
  async editTodo(postID: number, createTodoDTO: CreateTodoDTO): Promise<Todo> {
    await this.deleteTodo(postID);
    this.todos.push(createTodoDTO);

// return last added item
    return this.todos.at(-1);
  }

// Deletes a todo from the array
  async deleteTodo(todoID: number): Promise<any> {
    const todoIndex = this.todos.findIndex((todo) => todo.id === todoID);
    return this.todos.splice(todoIndex, 1);
  }
}

The code above implements a simple CRUD (Create, Retrieve, Update, and Delete) operation using simple JavaScript array manipulations since we are not working with a real database.

The comments in the code make it self-explanatory.

Creating Modules

In Nest.js, modules are used to organize your project into features and allow you to separate different features for easy structuring.

The module is a class annotated with a @Module() decorator. It helps to keep the application structure organized.

nest generate module todo

The command above will generate a new module named todo.module.ts for the application and update the root module for it by automatically importing the newly created TodoModule.

Inside the todo.module.ts, you can wire up everything by importing your controllers’ providers, and Nest.js will set up everything.

Let’s take a look at how we wired up everything:

import { Module } from '@nestjs/common';
import { TodoController } from './todo.controller';
import { TodoService } from './todo.service';
@Module({
  imports: [],
  controllers: [TodoController],
  providers: [TodoService],
})
export class AppModule {}

Nest, inside the TodoModule, we imported the todo.module.ts file, this should be done automatically if you use the command above.

import { Module } from '@nestjs/common';
import { TodoService } from './todos/todo.service';
@Module({
  imports: [TodoService],
})
export class AppModule {}

Lastly, we create our first DTO (data transfer object) to help define how data will be sent over the network and control how data will be posted from the application to the database.

// /nest-todo-app/src/todo/dto/create-todo.dto.ts

export class CreateTodoDTO {
  readonly id: number;
  readonly title: string;
  readonly description: string;
  readonly isDone: boolean;
}

Testing Nest.js framework

We will test our newly developed REST API with Postman and ensure we have the right data. You can read more about Postman and install it on your local machine if you don’t already have it.

Make sure your development server is still running or run the following command to get it up and running:

npm run start:dev

Open your Postman and test your backend API like below:

Suppose you have a response as above, congrats. You can test out the remaining endpoints.

Chapter 4: Advanced NestJS Guide

In the advanced NestJS Guide, what you will learn includes:

  • Database Connectivity using MongoDB and TypeORM
  • Authentication and Authorization with Nest.js
  • Real-world ticket ordering application with Nest.js
  • Write Unit Test for with Nest.js
  • Build your frontend with Nuxt.js
  • Deploy Nest.js to Heroku

Let me know in the comments section. I will share it with you.

Don't Stop Learning

Continue reading the Advanced NestJS Guide for $9.99 only or Get instant access to all current and upcoming courses and content through subscription.

Resources

  1. NestJS: The Complete Developer’s Guide is the best course I can recommend to learn and build full-featured backend APIs quickly with Nest, TypeORM, and Typescript. Includes testing and deployment!
  2. NestJS Zero to Hero – Modern TypeScript Back-end Development is another recommended course to learn NestJS. This is the course I used to get up and running with NestJS.
  3. Official Documentation
  4. Getting Started with NestJS
  5. Developing a Secure API with NestJS: Getting Started
  6. NestJS Crash Course By Brad Traversy

Conclusion: NestJS

NestJS typescript framework is a backend framework used to create scalable and reliable APIs.

It is an all-in-one typescript web framework that includes tools to handle every possible use case, from data persistence, validation, config management, testing, etc.

Also, the Typescript web framework is officially used in Nest.js to make sure writing clean and correct codes are achieved.

Now, it’s your turn to practice everything you have learned from this Nest.js tutorial until you master them by building real-world projects.

Let me know what you will be making. If none, comment “Nest.js is Great,” we may connect from there.

Whenever you're ready

There are 3 ways we can help you become a great backend engineer:

The MB Platform

Join 1000+ backend engineers learning backend engineering. Build real-world backend projects, learn from expert-vetted courses and roadmaps, track your learnings and set schedules, and solve backend engineering tasks, exercises, and challenges.

The MB Academy

The “MB Academy” is a 6-month intensive Advanced Backend Engineering BootCamp to produce great backend engineers.

Join Backend Weekly

If you like post like this, you will absolutely enjoy our exclusive weekly newsletter, Sharing exclusive backend engineering resources to help you become a great Backend Engineer.

Backend Tips, Every week

Backend Tips, Every week