Skip to main content
Advertisement

Node.js Overview

What is Node.js?

Node.js is a runtime environment that allows JavaScript to run outside the browser. Since Ryan Dahl introduced it in 2009, it has become the standard for server-side JavaScript.

Traditional web servers (Apache, Tomcat) occupy one thread per request. As concurrent users grow, threads scale linearly and memory/CPU are quickly exhausted. Node.js solves this problem with an event-driven, non-blocking I/O model.


V8 + libuv: The Two Engines of Node.js

┌─────────────────────────────────────┐
│ Node.js Runtime │
│ │
│ ┌──────────┐ ┌───────────────┐ │
│ │ V8 │ │ libuv │ │
│ │ (JS exec)│ │(async I/O) │ │
│ └──────────┘ └───────────────┘ │
│ │
│ ┌─────────────────────────────┐ │
│ │ Node.js Core API │ │
│ │ (fs, http, crypto, ...) │ │
│ └─────────────────────────────┘ │
└─────────────────────────────────────┘

V8 Engine

A high-performance JavaScript engine developed by Google for Chrome. It compiles JavaScript code to machine code via JIT (Just-In-Time) compilation. Node.js embeds V8 to execute JavaScript on the server.

libuv

A cross-platform asynchronous I/O library written in C. It handles the event loop, thread pool, file system, and networking. Node.js's non-blocking nature is mostly thanks to libuv.


Event-Driven Non-Blocking I/O Model

Blocking vs Non-Blocking

Blocking halts the entire thread while reading a file:

// Blocking code (synchronous)
const fs = require('fs');

const data = fs.readFileSync('/large-file.txt', 'utf8'); // Thread stops here
console.log('File read complete:', data.length, 'bytes');
console.log('This runs only after the above finishes');

Non-blocking hands the I/O off to the background and immediately continues:

// Non-blocking code (asynchronous)
const fs = require('fs');

fs.readFile('/large-file.txt', 'utf8', (err, data) => {
if (err) throw err;
console.log('File read complete:', data.length, 'bytes');
});
console.log('This runs first!'); // Printed before file is read

The Event Loop

The core of Node.js. The mechanism for handling concurrency on a single thread:

   ┌──────────────────────────────────┐
│ Event Loop │
│ │
│ ┌──────────┐ │
│ │ timers │ setTimeout, setInterval
│ └─────┬────┘ │
│ │ │
│ ┌─────▼────────────┐ │
│ │ pending callbacks│ I/O errors │
│ └─────┬────────────┘ │
│ │ │
│ ┌─────▼──────┐ │
│ │ poll │ wait for I/O │
│ └─────┬──────┘ │
│ │ │
│ ┌─────▼──────┐ │
│ │ check │ setImmediate │
│ └─────┬──────┘ │
│ │ │
│ ┌─────▼─────────────┐ │
│ │ close callbacks │ │
│ └───────────────────┘ │
└──────────────────────────────────┘
// Verify event loop behavior
console.log('1: synchronous code');

setTimeout(() => console.log('3: setTimeout (0ms)'), 0);

Promise.resolve().then(() => console.log('2: Promise (microtask)'));

console.log('1-2: more synchronous code');

// Output order:
// 1: synchronous code
// 1-2: more synchronous code
// 2: Promise (microtask)
// 3: setTimeout (0ms)

The npm Ecosystem

npm (Node Package Manager) is the world's largest open-source package registry with over 2.3 million packages.

package.json Basics

# Initialize a new project
mkdir my-project && cd my-project
npm init -y

Generated package.json:

{
"name": "my-project",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "node index.js",
"test": "jest"
},
"keywords": [],
"author": "",
"license": "ISC"
}

Installing Packages

# Install a regular dependency
npm install express

# Install a dev dependency
npm install --save-dev nodemon

# Install globally
npm install -g pm2

# Check package.json after installation
cat package.json

node_modules Structure

my-project/
├── node_modules/
│ ├── express/
│ ├── body-parser/
│ └── ...
├── package.json
└── package-lock.json

Always add to .gitignore:

node_modules/

Node.js vs Browser Differences

ItemNode.jsBrowser
Global objectglobalwindow
DOM APINonedocument, navigator, etc.
File systemAccessible via fs moduleInaccessible (security)
Module systemCommonJS(require) + ESMESM(import)
Execution envServer / local machineSandboxed environment
Process mgmtprocess objectNone
// Only works in Node.js
const os = require('os');
console.log('Platform:', process.platform);
console.log('Node version:', process.version);
console.log('CPU cores:', os.cpus().length);
console.log('Memory:', Math.round(os.totalmem() / 1024 / 1024 / 1024), 'GB');

// Global objects that don't exist in browsers
console.log(typeof window); // undefined (Node.js)
console.log(typeof global); // object (Node.js)
console.log(typeof process); // object (Node.js)

Module System Differences

// Node.js CommonJS (default)
const express = require('express');
module.exports = { myFunction };

// Node.js ESM (requires "type": "module" in package.json)
import express from 'express';
export { myFunction };

Node.js Version Management

Node.js releases even-numbered LTS versions and odd-numbered Current versions:

VersionTypeNotes
20.xLTS (Active)Long-term support, recommended for production
22.xLTS (Maintenance)Security patches only
23.xCurrentLatest features, experimental
24.xIn developmentFuture version

Managing Versions with nvm

# Install nvm (macOS/Linux)
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash

# Install a specific version
nvm install 20
nvm install 22

# Switch versions
nvm use 20

# Set default version
nvm alias default 20

# List installed versions
nvm ls

# Check current version
node --version
npm --version

Hands-On: Running Your First Node.js Server

Basic HTTP Server

// server.js
const http = require('http');

const hostname = '127.0.0.1';
const port = 3000;

const server = http.createServer((req, res) => {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain; charset=utf-8');
res.end('Hello from your Node.js server!\n');
});

server.listen(port, hostname, () => {
console.log(`Server running at: http://${hostname}:${port}/`);
});
node server.js
# Server running at: http://127.0.0.1:3000/

curl http://127.0.0.1:3000
# Hello from your Node.js server!

JSON API Server

// api-server.js
const http = require('http');

const users = [
{ id: 1, name: 'Alice', role: 'admin' },
{ id: 2, name: 'Bob', role: 'user' },
{ id: 3, name: 'Charlie', role: 'user' },
];

const server = http.createServer((req, res) => {
res.setHeader('Content-Type', 'application/json; charset=utf-8');

if (req.url === '/users' && req.method === 'GET') {
res.statusCode = 200;
res.end(JSON.stringify({ success: true, data: users }));
} else if (req.url === '/health') {
res.statusCode = 200;
res.end(JSON.stringify({ status: 'ok', uptime: process.uptime() }));
} else {
res.statusCode = 404;
res.end(JSON.stringify({ success: false, message: '404 Not Found' }));
}
});

server.listen(3000, () => {
console.log('API Server: http://localhost:3000');
console.log('Endpoints: GET /users, GET /health');
});

Using the REPL

# Start Node.js REPL
node

# Inside the REPL
> const arr = [1, 2, 3, 4, 5]
> arr.filter(n => n % 2 === 0)
[ 2, 4 ]
> arr.reduce((acc, n) => acc + n, 0)
15
> .exit

Common Node.js Use Cases

When Node.js Shines

  • Real-time applications: Chat, notifications, game servers — event-driven model excels here
  • API servers: RESTful API, GraphQL — fast JSON processing
  • Microservices: Lightweight, fast startup time
  • Streaming services: Large file/media streaming
  • CLI tools: npm, webpack, ESLint and most JS tooling is Node.js-based

When to Consider Alternatives

  • CPU-intensive computation: Image/video processing, encryption, machine learning — Python/Go is more suitable
  • Multi-threading needs: Single-threaded by default (solvable with worker_threads)
  • Memory-intensive work: V8 heap memory limit (~1.5GB default)

Pro Tips

Using the process Object

// Print process information
console.log('Node version:', process.version);
console.log('Platform:', process.platform); // win32, linux, darwin
console.log('Architecture:', process.arch); // x64, arm64
console.log('PID:', process.pid);
console.log('Working directory:', process.cwd());
console.log('Executable path:', process.execPath);

// Environment variables
process.env.NODE_ENV = 'production';
console.log('Environment:', process.env.NODE_ENV);

// Process exit
process.on('exit', (code) => {
console.log(`Process exited with code: ${code}`);
});

// Clean exit
process.exit(0);
// Error exit
process.exit(1);

Measuring Performance

// Measure execution time
const { performance } = require('perf_hooks');

const start = performance.now();

let sum = 0;
for (let i = 0; i < 1_000_000; i++) {
sum += i;
}

const end = performance.now();
console.log(`Execution time: ${(end - start).toFixed(2)}ms`);
console.log(`Result: ${sum}`);

// console.time method
console.time('loop');
let total = 0;
for (let i = 0; i < 1_000_000; i++) total += i;
console.timeEnd('loop');

Monitoring Memory Usage

// Check memory usage
const used = process.memoryUsage();
console.log('Memory usage:');
for (const [key, value] of Object.entries(used)) {
console.log(` ${key}: ${Math.round(value / 1024 / 1024 * 100) / 100} MB`);
}
// heapUsed: heap memory currently in use
// heapTotal: total heap size
// rss: total memory allocated by the OS
// external: memory used by C++ bindings
Advertisement