London, United Kingdom

(+44) 07788.377.460 [email protected]

NodeJS vs Node.JS vs NestJS vs TypeScript vs server-side JavaScript

Does server-side JavaScript mean NodeJS?

Is Node.JS the same as nodejs?

Yes, but NO

“NodeJS is server-side JavaScript, but server-side JavaScript is not NodeJS. “

from the interweb

## tl;dr

So the answer is an hesitating “yes… but actually no“.

Server-side JavaScript is the concept, Node.js is one implementation (arguably the most popular) that makes it happen. More specifically, Node.js is an open source implementation and runtime environment specifically designed to enable server-side JavaScript execution. 

Node.js is closely tied to server-side JavaScript but they’re not exactly the same. And while there’s no practical difference between Node.js, NodeJS,`nodejs` or `node`, there are some semantic differences though.

## a bit more

The server-side JavaScript concept refers to any JS code that runs on the server rather than web browser; it may handle web requests, interact with databases, perform backend logic, etc. The name Node.js refers to the open-source runtime that allows JavaScript to be executed server-side. There are other ways to achieve server-side JavaScript, including NodeJS, Deno, and older technologies like Netscape’s LiveWire or Microsoft’s ASP with JScript.

The official name of the platform is Node.js (with a capital “N” and a period), however for convenience it is sometimes shortened to “NodeJS” (or even just “node”). The all-lower-case “nodejs”, “node.js”, or “node” may specifically mean the command to run in the command prompt (which might be different across operating systems and configurations) to access the Node.js runtime. 


## There can be only one: NodeJS!

I say, let us merge “server-side JavaScript” together with “nodejs”, and “Node.js”, and “node”, all into NodeJS, which is in fact a colloquially accepted term anyways as there is no practical difference between them (unless you want to get really pedantic about it #triggered).

This article assumes NodeJS is server-side JS. This is for consistency and to avoid  further confusion, as I’m mostly going to reference the runtime, not the actual command.

But wait…

But have you heard of NestJS? Not to be confused with NuxtJS, nor NextJS though. How about TypeScript? Oh, JavaScript can be a bit much sometimes… 

OK, so Node.JS vs NestJS vs TypeScript?

So TypeScript is strongly typed (i.e. adds static type definitions) JavaScript; it’s a superset of JavaScript meaning any valid JavaScript code is also valid TypeScript code.

NestJS is a framework built on top of Node.js, which enforces a modular architecture and adds structure for building web applications, while providing tools for dependency injection, routing, and more. NestJS supports TypeScript only!

NestJS -> TypeScript -> Node.js (NodeJS) -> JavaScript

FeatureNodeJSNestJS
TypeRuntime EnvironmentFramework Built on NodeJS
Language SupportJavaScriptTypeScript (only)
ArchitectureFlexible, no enforced structureModular, with well-defined structure
Learning CurveEasier to learn initiallySteeper learning curve due to structure
Use CasesWide variety of server-side appsLarge and complex web applications
Libraries & ModulesLarge ecosystem (npm)Built-in modules & npm

Node.js is a runtime environment that provides the core functionality to execute JavaScript code on the server, whereas NestJS offers additional features and structure to simplify web development, together with static typing by use of TypeScript. NestJS is specifically designed for building large and complex web applications where structure and maintainability are crucial, leading to cleaner and more maintainable code.

Did any of that make any sense at all?


Moving on to the event loop in JavaScript… Oh, boy! You know how NodeJS can handle multiple operations concurrently without being multi-threaded? Well this is at the core of it all.

## The Event Loop

NodeJS’ best selling feature is its event loop and its ability to handle multiple operations concurrently, without being multi-threaded. It is a single-threaded event loop model able to handle asynchronous, non-blocking tasks.

When a non-blocking / asynchronous operation is initiated (e.g., reading a file, making an HTTP request, or querying a database), NodeJS offloads this to the system kernel. The kernel notifies NodeJS when the operation completes, at which point the corresponding callback is added to the event loop’s task queue, also known as a macrotask. The event loop will process tasks from this queue when it’s in the appropriate phase. Microtasks (operations like `process.nextTick()` and resolved Promises) are processed after the current macrotask completes but before the event loop continues to the next phase. All microtasks in the queue are handled with high priority, before the loop continues to the next task in the queue.

Phases of the Event Loop:

  1. Timers: handles callbacks scheduled by setTimeout() and setInterval(). When the event loop enters this phase, it checks the timers and executes the callbacks if the specified time has elapsed.
  2. Pending Callbacks: executes I/O callbacks that were deferred to the next loop iteration.
  3. Idle, Prepare: internal phases used by Node.js to handle certain internal tasks. They are not typically manipulated directly by developers.
  4. Poll: retrieves new I/O events and executes I/O-related callbacks. If there are no timers set, the event loop can block here and wait for new events, making it efficient for handling multiple I/O operations.
  5. Check: execution of callbacks from setImmediate(). These callbacks are executed immediately after the poll phase.
  6. Close Callbacks: execute close callbacks, such as those for closed network connections.

The event loop in JavaScript, whether on the client side or the server side, is a crucial concept for handling asynchronous operations. It allows JavaScript to perform many tasks concurrently without the complexity of multi-threading. It enables efficient and scalable handling of asynchronous operations by delegating I/O operations to the system kernel and leveraging non-blocking I/O, thus efficiently managing high I/O workloads.


This video might be able to illustrate better how it all works. It has certainly helped me!


Addendum on TypeScript

Sample TypeScript code that implements enums, interfaces, abstract classes, and custom objects:
enum VehicleType {
    car = "Car",
    truck = "Truck",
    bus = "Bus",
    van = "Van",
    motorcycle = "Motorcycle",
}

enum EngineType {
    petrol = "Petrol",
    diesel = "Diesel",
    hybrid = "Hybrid",
    electric = "Electric",
}

interface Automobile {
    type: VehicleType;
    manufactured: string;
    model: string;
    year: number;
    engineType ? : EngineType;
    mileage ? : number;
}
  
abstract class MotorVehicle implements Automobile {
    public constructor(
        public type: VehicleType,
        public manufactured: string,
        public model: string,
        public year: number,
        public engineType ? : EngineType,
        public mileage ? : number
    ) {
        console.log("Making automobile: " + this.manufactured + " " + this.model + " (" + this.year + ") " + this.engineType + " " + this.type);
    }
}

class Car extends MotorVehicle {
    // public type: CarType = CarType.car;
    public constructor(
        public manufactured: string,
        public model: string,
        public year: number,
        public engineType ? : EngineType,
        public mileage: number = 0,
    ) {
        super(VehicleType.car, manufactured, model, year, engineType, mileage);
    }
}

class Van extends MotorVehicle {
    public constructor(
        public manufactured: string,
        public model: string,
        public year: number,
        public engineType ? : EngineType,
        public mileage: number = 0,
    ) {
        super(VehicleType.van, manufactured, model, year, engineType, mileage);
    }
}

class Bus extends MotorVehicle {
    public constructor(
        public manufactured: string,
        public model: string,
        public year: number,
        public engineType ? : EngineType,
        public mileage: number = 0,
    ) {
        super(VehicleType.bus, manufactured, model, year, engineType, mileage);
    }
}

const fleet = new Set<Automobile>();

const ToyotaCorolla: Car = {
    manufactured: "Toyota",
    model: "Corolla",
    year: 2021,
    type: VehicleType.car,
    engineType: EngineType.hybrid,
    mileage: 6500,
};
fleet.add(ToyotaCorolla);

const FordTransit: Van = {
    manufactured: "Ford",
    model: "Transit",
    year: 2019,
    type: VehicleType.van,
    engineType: EngineType.petrol,
    mileage: 15000,
};
fleet.add(FordTransit);

const ElectricBus: Bus = {
    manufactured: "Red Bus",
    model: "Double Decker",
    year: 2022,
    type: VehicleType.bus,
    engineType: EngineType.electric,
    mileage: 0,
};
fleet.add(ElectricBus); 

fleet.forEach(function(vehicle: Automobile) {
    let theMessage = "Motor vehicle: " 
        + vehicle.manufactured + " " + vehicle.model + ", "
        + vehicle.engineType + " " + vehicle.type
        + " (" + vehicle.year + ")";
    console.log(theMessage);

    /* console.log(vehicle) */;
})

The above sample TypeScript code showcases how to implement an interface containing custom typed attributes, and the creation of objects from classes with encapsulated logic.