A

Node.js

nodejs javascript runtime backend server-side npm v8

Node.js

Node.js is a JavaScript runtime built on Chrome's V8 engine that allows you to run JavaScript on the server. Created by Ryan Dahl in 2009, Node.js revolutionized web development by enabling developers to use JavaScript for both frontend and backend code. It remains the most mature and widely-used JavaScript runtime for server-side development.

What is Node.js?

Node.js is a runtime environment that executes JavaScript outside the browser:

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

const server = http.createServer((req, res) => {
  res.writeHead(200, { 'Content-Type': 'text/plain' });
  res.end('Hello from Node.js!');
});

server.listen(3000, () => {
  console.log('Server running on http://localhost:3000');
});

Run with: node server.js

Key Features:

  • V8 Engine: Same engine as Chrome
  • Event-driven: Non-blocking I/O
  • Single-threaded: Uses event loop for concurrency
  • npm: Largest package ecosystem
  • Cross-platform: Windows, macOS, Linux

Why Node.js?

1. Massive Ecosystem (npm)

npm is the largest package registry in the world:

npm install express
npm install react
npm install lodash

Stats:

  • 2.5+ million packages
  • Billions of downloads per week
  • Package for almost anything

2. JavaScript Everywhere

Use the same language for frontend and backend:

// Shared code between frontend and backend
export function validateEmail(email) {
  return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
}

// Use in Node.js backend
const { validateEmail } = require('./validators');
if (!validateEmail(req.body.email)) {
  res.status(400).json({ error: 'Invalid email' });
}

// Use in React frontend
import { validateEmail } from './validators';
if (!validateEmail(email)) {
  setError('Invalid email');
}

3. Async/Non-blocking I/O

Handle many concurrent connections efficiently:

const fs = require('fs').promises;

// Non-blocking file operations
async function readFiles() {
  try {
    const [file1, file2, file3] = await Promise.all([
      fs.readFile('file1.txt', 'utf8'),
      fs.readFile('file2.txt', 'utf8'),
      fs.readFile('file3.txt', 'utf8'),
    ]);
    console.log('All files read concurrently');
  } catch (error) {
    console.error(error);
  }
}

4. Industry Standard

Used by major companies:

  • Netflix: Entire UI built on Node.js
  • LinkedIn: Migrated from Ruby to Node.js
  • Uber: Real-time platform
  • PayPal: Backend services
  • NASA: Mission control systems

5. Great for Real-time Applications

Perfect for WebSockets and real-time features:

const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8080 });

wss.on('connection', (ws) => {
  console.log('Client connected');

  ws.on('message', (message) => {
    // Broadcast to all clients
    wss.clients.forEach((client) => {
      if (client.readyState === WebSocket.OPEN) {
        client.send(message);
      }
    });
  });
});

The Event Loop

Node.js uses a single-threaded event loop:

console.log('1. Start');

setTimeout(() => {
  console.log('3. Timeout callback');
}, 0);

Promise.resolve().then(() => {
  console.log('2. Promise callback');
});

console.log('1. End');

// Output:
// 1. Start
// 1. End
// 2. Promise callback
// 3. Timeout callback

How it works:

  1. Execute synchronous code
  2. Process microtasks (Promises)
  3. Process macrotasks (setTimeout, setInterval)
  4. Repeat

Core Modules

Node.js includes built-in modules:

File System (fs)

const fs = require('fs').promises;

// Read file
const content = await fs.readFile('file.txt', 'utf8');

// Write file
await fs.writeFile('output.txt', 'Hello World');

// Check if file exists
const exists = await fs.access('file.txt')
  .then(() => true)
  .catch(() => false);

// List directory
const files = await fs.readdir('./');

HTTP/HTTPS

const http = require('http');

const server = http.createServer((req, res) => {
  if (req.url === '/' && req.method === 'GET') {
    res.writeHead(200, { 'Content-Type': 'application/json' });
    res.end(JSON.stringify({ message: 'Hello!' }));
  } else {
    res.writeHead(404);
    res.end('Not Found');
  }
});

server.listen(3000);

Path

const path = require('path');

path.join('/users', 'john', 'documents');  // /users/john/documents
path.resolve('file.txt');  // Absolute path
path.extname('file.txt');  // .txt
path.basename('/path/to/file.txt');  // file.txt
path.dirname('/path/to/file.txt');  // /path/to

OS

const os = require('os');

os.platform();  // 'darwin', 'win32', 'linux'
os.cpus();      // CPU info
os.totalmem();  // Total memory
os.freemem();   // Free memory
os.homedir();   // Home directory

Process

// Environment variables
console.log(process.env.NODE_ENV);

// Command line arguments
console.log(process.argv);

// Exit
process.exit(0);

// Event handlers
process.on('uncaughtException', (error) => {
  console.error('Uncaught exception:', error);
  process.exit(1);
});

Package Management

npm (Node Package Manager)

# Initialize project
npm init
npm init -y  # Skip questions

# Install packages
npm install express
npm install --save-dev nodemon
npm install -g typescript

# Install from package.json
npm install

# Update packages
npm update
npm outdated

# Remove packages
npm uninstall express

# Run scripts
npm run dev
npm test

package.json

{
  "name": "my-app",
  "version": "1.0.0",
  "main": "index.js",
  "scripts": {
    "start": "node index.js",
    "dev": "nodemon index.js",
    "test": "jest"
  },
  "dependencies": {
    "express": "^4.18.0",
    "dotenv": "^16.0.0"
  },
  "devDependencies": {
    "nodemon": "^2.0.0",
    "jest": "^29.0.0"
  }
}

pnpm (Faster Alternative)

# Install pnpm
npm install -g pnpm

# Use like npm
pnpm install
pnpm add express
pnpm remove express

Benefits:

  • 2-3x faster than npm
  • Saves disk space (shared dependencies)
  • Stricter dependency resolution

Express

Minimal web framework:

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

app.use(express.json());

app.get('/', (req, res) => {
  res.json({ message: 'Hello World' });
});

app.post('/users', (req, res) => {
  const user = req.body;
  // Save user...
  res.status(201).json(user);
});

app.listen(3000, () => {
  console.log('Server running on port 3000');
});

Fastify

High-performance alternative to Express:

const fastify = require('fastify')();

fastify.get('/', async (request, reply) => {
  return { hello: 'world' };
});

fastify.listen({ port: 3000 });

NestJS

Enterprise framework with Angular-like structure:

import { Controller, Get } from '@nestjs/common';

@Controller('users')
export class UsersController {
  @Get()
  findAll() {
    return ['user1', 'user2'];
  }
}

Koa

From the Express team, uses async/await:

const Koa = require('koa');
const app = new Koa();

app.use(async (ctx) => {
  ctx.body = 'Hello World';
});

app.listen(3000);

Working with Databases

MongoDB (Mongoose)

const mongoose = require('mongoose');

await mongoose.connect('mongodb://localhost/myapp');

const userSchema = new mongoose.Schema({
  name: String,
  email: { type: String, required: true, unique: true },
  age: Number,
});

const User = mongoose.model('User', userSchema);

// Create
const user = await User.create({
  name: 'Alice',
  email: '[email protected]',
  age: 25,
});

// Find
const users = await User.find({ age: { $gt: 18 } });
const alice = await User.findOne({ email: '[email protected]' });

// Update
await User.updateOne({ _id: userId }, { age: 26 });

// Delete
await User.deleteOne({ _id: userId });

PostgreSQL (Prisma)

// schema.prisma
model User {
  id    Int     @id @default(autoincrement())
  email String  @unique
  name  String?
  posts Post[]
}

// JavaScript
const { PrismaClient } = require('@prisma/client');
const prisma = new PrismaClient();

// Create
const user = await prisma.user.create({
  data: {
    email: '[email protected]',
    name: 'Alice',
  },
});

// Find
const users = await prisma.user.findMany({
  where: { email: { contains: 'example.com' } },
  include: { posts: true },
});

// Update
await prisma.user.update({
  where: { id: 1 },
  data: { name: 'Alice Smith' },
});

Environment Variables

// .env
DATABASE_URL=postgresql://localhost/mydb
API_KEY=secret123
NODE_ENV=development

// Load with dotenv
require('dotenv').config();

const dbUrl = process.env.DATABASE_URL;
const apiKey = process.env.API_KEY;
const isDev = process.env.NODE_ENV === 'development';

Error Handling

Try/Catch with Async/Await

async function getUser(id) {
  try {
    const user = await database.findUser(id);
    return user;
  } catch (error) {
    console.error('Error fetching user:', error);
    throw new Error('User not found');
  }
}

Express Error Middleware

app.use((err, req, res, next) => {
  console.error(err.stack);
  res.status(500).json({
    error: 'Internal Server Error',
    message: err.message,
  });
});

Uncaught Errors

process.on('uncaughtException', (error) => {
  console.error('Uncaught Exception:', error);
  process.exit(1);
});

process.on('unhandledRejection', (reason, promise) => {
  console.error('Unhandled Rejection at:', promise, 'reason:', reason);
  process.exit(1);
});

Testing

Jest

// sum.js
function sum(a, b) {
  return a + b;
}
module.exports = sum;

// sum.test.js
const sum = require('./sum');

test('adds 1 + 2 to equal 3', () => {
  expect(sum(1, 2)).toBe(3);
});

test('adds negative numbers', () => {
  expect(sum(-1, -2)).toBe(-3);
});

Supertest (API Testing)

const request = require('supertest');
const app = require('./app');

describe('GET /users', () => {
  it('responds with json', async () => {
    const response = await request(app)
      .get('/users')
      .expect('Content-Type', /json/)
      .expect(200);

    expect(response.body).toHaveLength(2);
  });
});

Performance Optimization

Clustering

Use all CPU cores:

const cluster = require('cluster');
const http = require('http');
const os = require('os');

if (cluster.isMaster) {
  const numCPUs = os.cpus().length;

  for (let i = 0; i < numCPUs; i++) {
    cluster.fork();
  }

  cluster.on('exit', (worker) => {
    console.log(`Worker ${worker.id} died, restarting...`);
    cluster.fork();
  });
} else {
  // Worker process
  http.createServer((req, res) => {
    res.end('Hello from worker ' + cluster.worker.id);
  }).listen(3000);
}

Caching

const cache = new Map();

app.get('/users/:id', async (req, res) => {
  const { id } = req.params;

  // Check cache
  if (cache.has(id)) {
    return res.json(cache.get(id));
  }

  // Fetch from database
  const user = await db.getUser(id);

  // Cache for 5 minutes
  cache.set(id, user);
  setTimeout(() => cache.delete(id), 5 * 60 * 1000);

  res.json(user);
});

Compression

const compression = require('compression');
const express = require('express');

const app = express();
app.use(compression());  // Gzip responses

Node.js vs Alternatives

Feature Node.js Bun Deno
Engine V8 JavaScriptCore V8
Speed Good Excellent Good
Maturity Very Mature New Moderate
Ecosystem Huge (npm) Growing Moderate
TypeScript Via ts-node Native Native
Package Manager npm/pnpm/yarn Built-in URL imports
Best For Production apps Performance TypeScript

Deployment

Traditional Server

# Install Node.js on server
# Copy your code
# Install dependencies
npm install --production

# Start with PM2 (process manager)
npm install -g pm2
pm2 start app.js
pm2 startup  # Start on boot

Docker

FROM node:18-alpine

WORKDIR /app

COPY package*.json ./
RUN npm install --production

COPY . .

EXPOSE 3000
CMD ["node", "index.js"]

Cloud Platforms

  • Vercel: vercel deploy
  • Heroku: git push heroku main
  • AWS: Elastic Beanstalk, Lambda
  • Google Cloud: App Engine, Cloud Run
  • Azure: App Service

Common Pitfalls

1. Callback Hell

// ❌ Bad - callback hell
fs.readFile('file1.txt', (err, data1) => {
  if (err) return console.error(err);
  fs.readFile('file2.txt', (err, data2) => {
    if (err) return console.error(err);
    fs.readFile('file3.txt', (err, data3) => {
      if (err) return console.error(err);
      console.log(data1, data2, data3);
    });
  });
});

// ✓ Good - async/await
try {
  const [data1, data2, data3] = await Promise.all([
    fs.promises.readFile('file1.txt'),
    fs.promises.readFile('file2.txt'),
    fs.promises.readFile('file3.txt'),
  ]);
  console.log(data1, data2, data3);
} catch (error) {
  console.error(error);
}

2. Blocking the Event Loop

// ❌ Bad - blocks event loop
function fibonacci(n) {
  if (n <= 1) return n;
  return fibonacci(n - 1) + fibonacci(n - 2);
}

app.get('/fib/:n', (req, res) => {
  const result = fibonacci(Number(req.params.n));  // Blocks!
  res.json({ result });
});

// ✓ Good - offload to worker thread
const { Worker } = require('worker_threads');

app.get('/fib/:n', (req, res) => {
  const worker = new Worker('./fibonacci-worker.js');
  worker.postMessage(Number(req.params.n));
  worker.on('message', (result) => {
    res.json({ result });
  });
});

3. Not Handling Async Errors

// ❌ Bad - unhandled promise rejection
app.get('/users', (req, res) => {
  database.getUsers()  // Returns promise
    .then(users => res.json(users));
  // Missing .catch()!
});

// ✓ Good - handle errors
app.get('/users', async (req, res, next) => {
  try {
    const users = await database.getUsers();
    res.json(users);
  } catch (error) {
    next(error);
  }
});

Key Takeaways

  • Most mature JavaScript runtime
  • Huge ecosystem with npm
  • Industry standard for production
  • Event-driven non-blocking I/O
  • Great for real-time apps and APIs
  • Use pnpm instead of npm for better performance
  • Consider alternatives (Bun, Deno) for new projects

Node.js revolutionized JavaScript development and remains the production-ready choice for server-side JavaScript. While newer runtimes like Bun offer better performance, Node.js's maturity, ecosystem, and industry adoption make it the safe choice for most projects.

Last updated: October 16, 2025