NestJS vs TotalJS vs AdonisJS: Hello World Performance
In this quick article, we’ll take a look at the performance differences between three popular & opinionated frameworks in the Node world:
- NestJS: Nest (NestJS) is a framework for building efficient, scalable Node.js server-side applications. It uses progressive JavaScript, is built with and fully supports TypeScript (yet still enables developers to code in pure JavaScript) and combines elements of OOP (Object Oriented Programming), FP (Functional Programming), and FRP (Functional Reactive Programming).
- TotalJS: Total.js Platform is a collection of server-side & client-side JavaScript/Node.js libraries, Web Components, Icons, practices, and Complete Node.js apps written in pure JavaScript, mostly without dependencies. Free and open-source.
- AdonisJS: AdonisJS is a TypeScript-first web framework for building web apps and API servers. It comes with support for testing, modern tooling, an ecosystem of official packages, and more.
We’ll be running the simplest ‘Hello World’ test. Let’s get started.
Application code
In all cases, the application code is either generated or taken from their official website.
NestJS
The nest app has been generated using the following command:
> nest new
The important parts of the app are as follows:
// main.ts
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
await app.listen(3000);
}T
// app.module.ts
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
@Module({
imports: [],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
// app.controller.ts
import { Controller, Get } from '@nestjs/common';
import { AppService } from './app.service';
@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
@Get()
getHello(): string {
return this.appService.getHello();
}
}
// app.service.ts
import { Injectable } from '@nestjs/common';
@Injectable()
export class AppService {
getHello(): string {
return 'Hello World!';
}
}
The app has been built using the following command:
> nest build
TotalJS
The application code has been copied from their official website:
require("total5");
ROUTE("GET /", function ($) {
$.text("Hello world!");
});
F.run({ port: 3000, release: true });
AdonisJS
The application has been generated using their CLI:
> npm init adonisjs@latest hello-world
There are a lot of files in generated code. The only relevant ones are:
// routes.ts
/*
|--------------------------------------------------------------------------
| Routes file
|--------------------------------------------------------------------------
|
| The routes file is used for defining the HTTP routes.
|
*/
import router from '@adonisjs/core/services/router'
router.get('/', async () => {
return "Hello World!"
})
Except for routes.ts, no other file has been changed in the generated code. In routes.ts, the only change is to return a string instead of JSON.
Test setup
All tests are executed on MacBook Pro M2 with 16G RAM and 8+4 CPU cores. The Node.js version is 22.2.0. The other versions are:
- NestJS: v10
- TotalJS: v5
- AdonisJS: v6.9
Bombardier test tool is used to generate HTTP load.
Results
Each test of 100 concurrent connections runs for 1M requests. A warm-up of 1K requests is given before taking readings.
The results in chart form are as follows:
Analysis
Something is not right with TotalJS (possibly on our test setup). Everytime we ran, the tests run for a much longer time. Some requests got hanged. TotalJS performs very well for minimum, Q25, median, and Q75 latencies. The outliers brought down the overall numbers for TotalJS. Additionally, TotalJS uses 900M of memory (memory leak?).
Overall, the winner is AdonisJS. It offers almost double performance at same or lesser cost.
Thanks for reading!