Express.js vs. Nest.js: Node Frameworks
Table of Contents
Get the latest news

Nest.js vs. Express.js: A Contest of Node Frameworks 

Gedalyah Reback | Senior Product Marketing Manager

Express.js vs. Nest.js: Node Frameworks
Table of Contents

What a time to be alive! The information age we are currently in has given us more data and choices about, well, everything. But let’s be honest, do any of us actually feel like we’re more informed than we were? 

Because all this information comes with more choices. Expanded choice is actually an “explosion of choice” – in other words, if the world were a restaurant, the menu is so long you spend more time choosing your order than actually eating it. It’s the same everywhere. It happens with medical information, with computers, and definitely with what software we choose to work with. A great example of this is would be the extremely large JavaScript and Node.js ecosystem. 

Node devs have a variety of implementations and frameworks to choose from, two of the most popular being Express.js and Nest.js. That duo sees a lot of competition on its tail from other networks and libraries that nearly function as networks, but for now, they are the main go-to answers to JS developers’ questions.

For starters, Express.js and Nest.js are among the most popular backend frameworks for Node.js development. Express is by far the most used of all the Node frameworks, but Nest is newer and more robust. Let’s dive into the differences and see which will be the best fit for you.

Popularity

Python ∙ Java ∙ Go ∙ .NET ∙ Ruby ∙ Node.js & MORE. Rookout covers it all

Try Rookout for free!

Express is still the most popular of the two frameworks, as it’s been around longer. But Nest, while more complicated, has been gaining ground consistently. If you grade their popularity based on GitHub stats, Express leads at around 58,000 to 49,000. As for forks, Express leads about 9,800 to 5,800. But Nest.js is in 2nd place for Node.js backend frameworks on both those marks. 

Last year’s State of JS survey considered programmers’ favorite frameworks and JS tools, including frameworks according to usage, satisfaction, and even awareness. Express sees much wider use (81%) versus Nest (45%) – after all, Nest is newer. Still, their favorability is neck and neck: 91% love Express; 88% love Nest. 

What is the consensus in surveys of users?

  1. Satisfaction: Express.js 88% vs. Nest.js 85%
  2. Usage: Express.js 81% vs, Nest.js 19% 

As you can see, usage isn’t the best indicator of applicability. Both score high on the satisfaction side in the State of JS survey, and they’ve both likewise hovered in that ~90 range for several years. There are plenty of people using both regularly, but when should they use them? And secondly, what sets them apart?

Express Code Samples

Express is relatively straight-forward when it comes to setting up a basic app. After installing, set Express as a constant with the require() function in your main app file. 

Install Express.js:

npm install express --save

Express.js Hello World

const express = require('express')
const app = express()
const port = 3000

app.get('/', (req, res) => {
  res.send('Hello World!')
})

app.listen(port, () => {
  console.log(`Example app listening on port ${port}`)
})

Nest.js Code Samples

Nest creates a more complex, but consistent architecture for its apps. It uses three primary files, by default, for every application: 1) main.ts, 2) app.service.ts, and 3) app.module.ts. To get started with Nest, download the npm package.

Install Nest.js:

npm i -g @nestjs/cli

Nest.js Hello World!

The Nest.js docs example implements Hello World in a separate file from main.ts: the app.service.ts file, which also depends on an app.module.ts file.

<strong>main.ts</strong>:

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { AppService } from './app.service';

async function bootstrap() {
  const app = await NestFactory.createApplicationContext(AppModule);
  const appService = app.get(AppService);
  console.log(appService.getHello());
}
bootstrap();

app.service.ts:

import { Injectable } from '@nestjs/common';

@Injectable()
export class AppService {
  getHello(): string {
    return 'Hello world!';
  }
}

app.module.ts:

import { Module } from '@nestjs/common';
import { AppService } from './app.service';

@Module({
  providers: [AppService],
})
export class AppModule {}

Express.js Philosophy: Unopinionated

Express.js is a “fast, unopinionated, minimalist web framework” if you go by its tagline. It’s a thin layer of features on top of Node.js, reflecting a cautious approach to augmenting Node. It also serves as part of the foundation of many other frameworks (not just Nest.js). That list contains FoalTS, Feathers, KeystoneJS, Kraken, Expressive Tea, and a bunch more.

You can use Express.js together with other frameworks like Meteor.js or AngularJS. It’s also extremely accessible – simple and easy to learn. 

Express is considered unopinionated while Nest.js is very opinionated. Express reflects the general approach of Node.js. There is more than one way to spin an app. That can give project managers a lot of options when it comes to starting workflows. Nest’s main concern is that those numerous options can get confusing.

Nest.js Philosophy: Opinionated

Nest.js is itself an extension, or abstraction on top of Express.js, using TypeScript as its main language instead of JavaScript, as well as dependency injection and modularity as part of its opinionated approach to coding (more on that later).

Kamil Myśliwiec, Nest’s creator, saw a gap for scalable server-side development for Node apps, It is also dubbed ‘Angular for the Backend’ by some, given Angular’s inspiration for Nest.js’s structure. On the heels of that approach, Nest.js functions as an abstraction layer on top of other frameworks like Express.js or Fastify (or to look at it another way, treats Express.js more like a library). Nest also defaults to TypeScript as its lingua franca, which itself adds structure to vanilla JS. 

Nest.js’s philosophy builds off a “convention over configuration” approach. It relies on modules to break code into digestible, almost brick-stackable sections, adding a lot of order to chaos. Nest also imposes dependencies, filters, guards, and controllers to create consistent approaches to app architecture. All in all, as with any prescriptive framework, a lot can be prepped out of the box – middleware, logging and error handling, parsing, and more. 

Modularity becomes a major factor in comparing how the two networks tackle core tasks. There are a lot of differences to consider, but let’s take a look at just a few: routing, middleware, and observability.

Express vs. Nest on Routing

Routing is the process by which an app or one of its components responds to a client request at an endpoint. Routing can be done via different methods and can create paths to multiple destinations. Specify a ‘callback function’ (a.k.a., a ‘handler function’) for the app to call when it gets a request. What the function does will depend on 1) which endpoint the request is routed through, and 2) which HTTP method it is using.

const express = require('express')
const app = express()

app.get('/yankees', (req, res) => {
  res.send('yankees')
})

Legend: Route MethodRoute PathRoute Parameter — Route Handler — app.route() 

You can specify parameters for the route with the req.params object.

const express = require('express')
const app = express()

app.route('/hitting-stats)
  .get(‘/hitting-stats/:player-name/homeruns:homerun-number’, (req, res) => {
    res.send('req.params')
  })
  .post((req, res) => {
    console.log('Batter added')
    next()
  })
  .put((req, res) => {
    res.send('Update batter stats')
  })

Nest.js uses a routing module to accomplish this. Use the RouterModule from the @nestjs/core package to match up the @controller decorator and @method decorator. You can also create a heirarchy of modules through the route/path chosen. Consider this example based on the one provided by the Nest.js docs.

RouterModule.register([
  {
    path: 'admin',
    module: AdminModule,
    children: [
      {
        path: 'metrics',
        module: MetricsModule,
      },
    ],
  },
]);

Nest vs. Express on Middleware

Middleware is at the center of Node.js frameworks and apps. It comes in the middle of the request/response cycle. For Express, by their own admission (via its documentation), Express offers “minimal functionality” and is “essentially

There’s router-level, error-handling, and application-level middleware. It can be built-in or provided by a third party. As of Express 4.0, there are only three purely built-in middleware functions specifically for static assets, URL-encoded data, and JSON. All of them operate as modules.

Nest middleware is equivalent to Express middleware, according to Nest.js documentation. But with the structure Nest offers, its implementation can be slightly different. You can use custom Nest-native middleware in a class though using the special NestMiddleware interface in the @nestjs/common package. You can also do it through a function.

Debugging

Debugging Express.js

The Express.js debug augments console.log. You have to configure it to run for any apps you generate in Express. So if you generate an app with the express <app-name> command, configure debugging with:

DEBUG=ExpressjsappImade:* node ./bin/www

The command DEBUG=express* will display all internal logs – routing, middleware, requests, responses, and application mode.

DEBUG=express:* node index.js

There are five debug parameters in Express.js to know:

  1. DEBUG
  2. DEBUG_COLORS – Use color highlighting with the debug output
  3. DEBUG_DEPTH – How deep you go with your debug log information
  4. DEBUG_FD – A description of the file where to write debug output
  5. DEBUG_SHOW_HIDDEN – Get granular and look at hidden properties in the logs

Debugging Nest.js

Debugging Nest.js isn’t as complicated as it might first seem. Nest currently lacks specific docs about debugging, which might be confusing given all the moving parts in the Nest architecture.

For a basic Nest.js app, you can go through VSCode, IntelliJ, or WebStorm via the package.json file to debug. This approach is more classic debugging, where you would edit code under “scripts” in the configuration file:

"start:debug:" "nest start --debug --watch" 

Then, in the terminal, run the script:

npm run start:debug

The quicker live debugging approach will debug the running application without having to redeploy or add anything to the code.

Rookout uses non-breaking breakpoints to allow the Nest.js app to continue running without code edits, stopping the app, or reloading it. Download the npm for Rookout, then configure the app as such:

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

const rookout = require('rookout'); rookout.start({ token: 'somerandomnumbers123457593903209' })

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

}
bootstrap();

Conclusion

Express and Nest bring competing philosophies to developing Node applications. Express is a minimal tweaking of what Node offers, while Nest literally builds on Express’s contributions to offer a more complex, but highly guided experience. The more organized the team is, the better to rely strictly on Express. But Nest.js offers more than just the developer’s equivalent of bumpers for bowling lanes. It embraces and offers fuller support for TypeScript, itself becoming more common. 

Either way, both add a layer of abstraction to Node.js that can demand more when it comes to observability and debugging. You can trial Rookout’s live debugger in Node.js for free, and come back for more tutorials and news about Node.js.

Rookout Sandbox

No registration needed

Play Now