Using NestJS with Express or Fastify

Choose the right platform for your requirement

As you might be aware, NestJS is a relatively new framework within the NodeJS ecosystem. It fully supports Typescript and uses principles of Object-Oriented Programming. We can use NestJS to build server-side applications (think microservices or REST APIs).

Over the years, NestJS has grown in popularity by leaps and bounds. If Github is any indication of a framework’s position within the development community, NestJS is on second place with almost 51K stars (at the time of writing). This is a pretty good number compared with ExpressJS having almost 58K stars despite being around for much longer.

Even if we consider Google Trends, the search term NestJS has seen a massive worldwide jump in search interest during the last couple of years.

image.png

In my view, it is beneficial for developers to explore NestJS. Along with the advantage of being in high demand, NestJS also offers a much more disciplined way of building applications in the NodeJS ecosystem. While it does make things more opinionated, it has more or less done what Spring Boot did for the Java ecosystem.

However, as with all frameworks, NestJS also has its own quirks. In the background, NestJS also uses HTTP server frameworks such as Express and Fastify. Basically, NestJS provides a layer of abstraction over Express and Fastify frameworks. But it also exposes their APIs to the developer. This helps developers use any available third-party package for the underlying server framework.

The question, however, is whether we should use Express or Fastify to build NestJS applications? And how should we go about enabling one of them for our NestJS application? In this post, both the questions will be answered.

For latest posts delivered right into your mailbox, subscribe to my publication on Substack for FREE.

1 - How to generate a NestJS Project?

There are a couple of options to get started with a NestJS project.

  • Using the Nest CLI

  • Cloning a starter project

In my opinion, it is better to use the Nest CLI. Apart from helping to scaffold a project, Nest CLI also provides several other features such as generating modules and controllers.

In order to use the Nest CLI, we first need to install the @nestjs/cli package globally using NPM. You would need NodeJS and NPM installed on your system to run the below command.

$ npm i -g @nestjs/cli

The -g flag stands for global. Once the installation is complete, we can generate a new project using the CLI.

$ nest new flight-service

This command will create a new project directory flight-service with initial NestJS files as well as supporting modules. It will also generate the basic structure of the project.

When you execute the above command, it will prompt you for a choice of package manager. You can choose between npm or yarn. For our demo, we will go with npm.

While Nest CLI generates a project based on recommended best practices, we can also create a new project manually from scratch. To do so, we need to install the core NestJS and its supporting packages.

$ npm i --save @nestjs/core @nestjs/common rxjs reflect-metadata

Once the packages are installed, we can create our own project structure. Unless you have some very specific requirements, I won’t recommend going down this route. It would instead be better to stick with the CLI.

2 - What's inside a NestJS Project?

When we scaffold a project using the Nest CLI, we get a project directory with a bunch of sub-folders and files. The core files are present in the src directory itself.

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

There is a specific use for each file.

  • app.controller.ts - This is a basic controller with a single example route.

  • app.controller.spec.ts - This file contains the unit tests for the controller.

  • app.module.ts - The root module of our NestJS application

  • app.service.ts - A demo service class with a single method.

  • main.ts - The application entry file that creates the NestJS application instance.

As you can notice, all of these are Typescript files. NestJS supports both Typescript and vanilla Javascript. However, the creators of NestJS officially recommend using Typescript. The use of Typescript allows us to use the features of NestJS in a much better way.

This is how the main.ts file of our project looks like.

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
​
async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  await app.listen(3000);
}

bootstrap();

So, what is going on over here?

As discussed earlier, the main.ts file is the entry point to our NestJS Application. It contains an async function bootstrap() that will bootstrap our entire application. Bootstrapping means loading a particular program into the system's memory for execution. Essentially, it is the first piece of code that runs when we try to start our application.

On a high level, the bootstrap() function is creating a Nest application instance by using the core NestFactory class.

The NestFactory class is part of the @nestjs/core package. Basically, the NestFactory class exposes a few static methods to create an application instance.

The create() method is one such static method. It takes the application root module as input and returns an application or the app object. This app object uses the INestApplication interface.

The app object has several methods we can use to control our application. However, currently we are only interested in starting up a basic HTTP listener using the listen() method.

The listen() method takes the port number as input and makes our application listen to incoming HTTP requests.

3 - Running the NestJS Project

Time to run our starter project.

We can run the project quite easily by executing the below command:

$ npm run start

This command starts up the application. The HTTP server will listen on port 3000 defined in the main.ts file. We can open a browser and navigate to http://localhost:3000 to see the default Hello, World! message hard-coded in the starter controller.

We can also start our application in watch-mode using the below command. In this mode, the local server will watch for code changes to automatically recompile and reload the server. This is great for development.

$ npm run start:dev

In case you are wondering, these commands are defined in the scripts section of the package.json file.

"scripts": {
    "start": "nest start",
    "start:dev": "nest start --watch",
}

4 - NestJS Platforms - Express and Fastify

Having understood the bootstrapping process and running our starter project, we can now focus on the original question.

How to configure our NestJS application to use Express or Fastify?

Technically, NestJS is a platform-agnostic framework. In other words, NestJS can work with any Node-based HTTP framework after creating an adapter for the same. The primary function of such an adapter is to proxy middleware and request handlers to the chosen platform.

Out of the box, NestJS supports two platforms:

  • platform-express - This uses the Express framework. By default, NestJS uses the Express platform and we don’t have to make any changes to the starter project if we intend to go with Express.

  • platform-fastify - This is the second option and it uses Fastify as the underlying HTTP framework. To use Fastify, we have to explicitly specify the same in the main.ts file.

NestJS supports these platforms by exposing their own interface. The platform-express exposes NestExpressApplication. We can instruct the NestFactory.create() method to return the app object of a specific platform type.

For example, to specify Express, we tweak the main.ts file and import NestExpressApplication from @nestjs/platform-express.

import { NestFactory } from '@nestjs/core';
import { NestExpressApplication } from '@nestjs/platform-express';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create<NestExpressApplication>(AppModule);
  await app.listen(3000);
}

bootstrap();

Of course, in the case of Express, we don’t need to do it explicitly. If nothing is specified in the create() method, our application will automatically use Express.

However, in order to work with Fastify, we need to install the platform-fastify package using the below command.

$ npm install --save @nestjs/platform-fastify

Once the installation is done, we need to enable FastifyAdapter within the main.ts file at the time of bootstrapping the NestJS application.

import { NestFactory } from '@nestjs/core';
import {
  FastifyAdapter,
  NestFastifyApplication,
} from '@nestjs/platform-fastify';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create<NestFastifyApplication>(
    AppModule,
    new FastifyAdapter()
  );
  await app.listen(3000, '0.0.0.0');
}

bootstrap();

As you can see, we pass the NestFastifyApplication type to the NestFactory.create() method. The NestFastifyApplication type is imported from the newly installed package. Also, the create() method takes an additional argument as input - an instance of FastifyAdapter class.

By default, Fastify listens on 127.0.0.1 only. Therefore, to accept connections on other hosts, we specify 0.0.0.0 in the call to the listen() method.

5 - NestJS Express vs Fastify

Now we know how to use Express or Fastify with NestJS. But when should we use one over the other?

In my view, this depends on what we are trying to achieve with the application.

The advantage of using Express is the large number of third-party libraries that are available in the Express ecosystem. It is a very mature framework with a great community support and documentation. Since it has been around for so long, it is also easy to find developers with knowledge about Express. Moreover, the platform-express doesn’t require you to perform any additional setups.

Fastify, on the other hand, is geared towards high-performance. According to the developers of Fastify, the framework can support up to 30,000 requests per second. In essence, Fastify promises high-performance with low overhead.


Ultimately, I feel that if you don’t have any crazy performance requirements, it might be better to stick with NestJS with Express as the underlying platform.

Have you been using NestJS in your projects? If yes, which platform did you go with - Express or Fastify? And what were your experiences using those platforms?

I would love to hear your views about the whole topic. So, please do share your thoughts in the comments section below.

Did you find this article valuable?

Support Saurabh Dashora by becoming a sponsor. Any amount is appreciated!