← Tutorials ☕ Java 🧩 DSA 🌿 Spring Boot 🚀 DevOps 🗂 MySQL 🏗 System Design ❓ FAQ 🌐 HTML 🔇 JavaScript ⚛ ReactJS 🌻 NodeJS 🐍 Python 🍏 MongoDB 📋 Cheatsheet
Tutorials › NodeJS

Introduction to Node.js

Beginner · 5 min read

Node.js is a runtime environment that lets you run JavaScript on the server side, built on Chrome's V8 engine. It uses an event-driven, non-blocking I/O model that makes it lightweight and efficient — ideal for real-time applications and APIs.

Why Node.js?

  • JavaScript everywhere — same language on frontend & backend
  • Non-blocking I/O — handles thousands of concurrent connections
  • npm ecosystem — 2 million+ packages
  • Great for REST APIs, microservices, real-time apps, CLIs
  • Used by Netflix, LinkedIn, Uber, PayPal

Node.js Event Loop

Node.js is single-threaded but handles concurrency via the event loop. When an async operation (file I/O, DB query, HTTP call) starts, Node delegates it to the OS/thread pool and continues processing other requests. When the operation completes, its callback is queued for execution.

💡 Node.js is not suitable for CPU-heavy operations (image processing, ML inference) — those block the event loop. Use worker threads or offload to a separate service.

Setup & npm

Beginner · 7 min read

# Install Node.js via https://nodejs.org (LTS recommended) node --version # v20.x or v22.x npm --version # 10.x # Initialize a project mkdir my-api && cd my-api npm init -y # creates package.json with defaults # Install packages npm install express mongoose dotenv bcrypt jsonwebtoken npm install --save-dev nodemon jest supertest # package.json scripts { "scripts": { "start": "node src/index.js", "dev": "nodemon src/index.js", "test": "jest" } } # Run npm run dev # auto-restart on file changes # Useful npm commands npm list # list installed packages npm outdated # show outdated packages npm update # update within semver range npm audit # check for vulnerabilities npm audit fix # auto-fix vulnerabilities npx # run package without installing globally

Module System (CJS / ESM)

Beginner · 8 min read

// CommonJS (CJS) — default in Node.js (.js files) // math.js function add(a, b) { return a + b; } const PI = 3.14159; module.exports = { add, PI }; // OR: exports.add = add; // main.js — require const { add, PI } = require('./math'); // local module const fs = require('fs'); // built-in const express = require('express'); // npm package // ES Modules (ESM) — add "type":"module" in package.json // math.mjs or with "type":"module" export const PI = 3.14159; export function add(a, b) { return a + b; } export default class Calculator { ... } // import import { add, PI } from './math.js'; import Calculator from './math.js'; import * as Math from './math.js'; // Dynamic import (works in both CJS and ESM) const { add } = await import('./math.js'); // __dirname and __filename (ESM — not available by default) import { fileURLToPath } from 'url'; import path from 'path'; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename);

File System (fs)

Beginner · 8 min read

const fs = require('fs'); const fsp = require('fs/promises'); // Promise-based (preferred) const path = require('path'); // Async read (callback) fs.readFile('data.txt', 'utf8', (err, data) => { if (err) throw err; console.log(data); }); // Promise-based (async/await) const data = await fsp.readFile('data.txt', 'utf8'); await fsp.writeFile('out.txt', 'Hello\n'); await fsp.appendFile('log.txt', 'New entry\n'); await fsp.unlink('temp.txt'); // delete file await fsp.mkdir('uploads', { recursive: true }); const files = await fsp.readdir('.'); // Sync (avoid in server code — blocks event loop) const config = JSON.parse(fs.readFileSync('config.json', 'utf8')); // Watch for changes fs.watch('./src', { recursive: true }, (event, filename) => { console.log(`${event}: ${filename}`); }); // path utilities path.join(__dirname, 'uploads', 'avatar.jpg') // OS-safe join path.resolve('./config.json') // absolute path path.extname('file.jpg') // '.jpg' path.basename('path/file.js') // 'file.js' path.dirname('path/file.js') // 'path'

path & os Modules

Beginner · 5 min read

const os = require('os'); const path = require('path'); // os — system information os.platform() // 'linux', 'darwin', 'win32' os.arch() // 'x64', 'arm64' os.cpus() // array of CPU info os.totalmem() // total RAM in bytes os.freemem() // free RAM in bytes os.homedir() // '/Users/aftab' os.tmpdir() // temp directory os.hostname() // machine name os.uptime() // seconds since boot os.EOL // '\n' (Linux/Mac) or '\r\n' (Windows) // Useful derived values const cpuCount = os.cpus().length; // for clustering const ramGB = os.totalmem() / 1024 ** 3; // path — cross-platform file paths path.sep // '/' on Linux/Mac, '\' on Windows path.delimiter // ':' on Linux/Mac, ';' on Windows (for PATH) path.parse('/home/user/file.txt') // { root:'/', dir:'/home/user', base:'file.txt', ext:'.txt', name:'file' } path.format({ dir: '/home', name: 'file', ext: '.txt' }) // '/home/file.txt'

EventEmitter

Intermediate · 8 min read

Node.js is event-driven. EventEmitter is the core class that allows objects to emit named events and attach listener functions.

const { EventEmitter } = require('events'); class OrderService extends EventEmitter { placeOrder(order) { // ... process order ... this.emit('order:placed', order); if (order.isPriority) this.emit('order:priority', order); } } const svc = new OrderService(); // on — persistent listener svc.on('order:placed', (order) => { console.log('New order:', order.id); sendEmail(order.customerEmail); }); // once — listener fires only once svc.once('order:priority', (order) => { alertAdmin(order); }); // off / removeListener const logFn = (o) => console.log(o); svc.on('order:placed', logFn); svc.off('order:placed', logFn); // error event (must always be handled!) svc.on('error', (err) => console.error('OrderService error:', err)); // Unhandled 'error' events crash the process svc.placeOrder({ id: 'ORD-001', customerEmail: 'a@b.com' });

Streams & Buffers

Advanced · 10 min read

Streams process data chunk-by-chunk instead of loading it all into memory. Essential for large files, video streaming, and pipe-based data pipelines.

const fs = require('fs'); const { Transform, pipeline } = require('stream'); const { promisify } = require('util'); const pipe = promisify(pipeline); // Readable stream — read large file without loading all in RAM const readable = fs.createReadStream('huge-file.csv', { encoding: 'utf8' }); readable.on('data', chunk => console.log('Chunk:', chunk.length)); readable.on('end', () => console.log('Done')); readable.on('error', err => console.error(err)); // Writable stream const writable = fs.createWriteStream('output.txt'); writable.write('line 1\n'); writable.end(); // Pipe (read → transform → write) — memory efficient const zlib = require('zlib'); await pipe( fs.createReadStream('input.txt'), zlib.createGzip(), // transform: compress fs.createWriteStream('input.txt.gz') ); // Custom Transform stream const upperCase = new Transform({ transform(chunk, encoding, callback) { this.push(chunk.toString().toUpperCase()); callback(); } }); // Buffer — raw binary data const buf = Buffer.from('Hello', 'utf8'); buf.toString(); // 'Hello' buf.toString('hex'); // '48656c6c6f' buf.toString('base64'); // 'SGVsbG8=' Buffer.alloc(16); // 16 zero bytes Buffer.concat([buf1, buf2]);

HTTP Module

Beginner · 7 min read

const http = require('http'); // Create a basic HTTP server const server = http.createServer((req, res) => { const { method, url, headers } = req; // Parse body (manual) let body = ''; req.on('data', chunk => body += chunk); req.on('end', () => { const parsed = body ? JSON.parse(body) : {}; res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ method, url, body: parsed })); }); }); server.listen(3000, () => console.log('Server on http://localhost:3000')); // HTTP client (make outgoing requests) const https = require('https'); https.get('https://api.github.com/users/torvalds', { headers: { 'User-Agent': 'my-app' } }, (res) => { let data = ''; res.on('data', chunk => data += chunk); res.on('end', () => console.log(JSON.parse(data))); });
💡 In real projects you'll use Express.js instead of the raw http module — it handles routing, middleware, and parsing for you.

Express.js Setup

Beginner · 8 min read

npm install express // src/index.js const express = require('express'); const app = express(); // Built-in middleware app.use(express.json()); // parse JSON body app.use(express.urlencoded({ extended: true })); // parse form data app.use(express.static('public')); // serve static files // Routes app.get('/', (req, res) => { res.json({ message: 'Hello from Express!' }); }); // Start server const PORT = process.env.PORT || 3000; app.listen(PORT, () => console.log(`Server running on port ${PORT}`));

Project Structure

src/ ├── index.js # entry: setup app, connect DB, start server ├── app.js # express app setup (middleware, routes) ├── routes/ │ ├── users.js │ └── products.js ├── controllers/ │ ├── userController.js │ └── productController.js ├── models/ │ └── User.js ├── middleware/ │ ├── auth.js │ └── errorHandler.js └── config/ └── db.js

Routing

Beginner · 8 min read

// routes/users.js const router = require('express').Router(); const { getUsers, getUser, createUser, updateUser, deleteUser } = require('../controllers/userController'); // RESTful routes router.get('/', getUsers); // GET /users router.get('/:id', getUser); // GET /users/42 router.post('/', createUser); // POST /users router.put('/:id', updateUser); // PUT /users/42 router.delete('/:id', deleteUser); // DELETE /users/42 module.exports = router; // app.js — mount router app.use('/api/users', require('./routes/users')); // Route parameters & query strings router.get('/:id/orders', (req, res) => { const { id } = req.params; // /users/42/orders const { page, limit } = req.query; // ?page=2&limit=10 res.json({ id, page, limit }); }); // chain routes on same path router.route('/:id') .get(getUser) .put(updateUser) .delete(deleteUser);

Middleware

Intermediate · 10 min read

Middleware functions have access to req, res, and next. They run in order and can modify the request, send a response, or pass control to the next middleware.

// Logger middleware function logger(req, res, next) { console.log(`[${new Date().toISOString()}] ${req.method} ${req.url}`); next(); // MUST call next() or request hangs } app.use(logger); // Rate limiter const rateLimit = require('express-rate-limit'); app.use('/api', rateLimit({ windowMs: 15 * 60 * 1000, // 15 min max: 100, // 100 requests per window message: 'Too many requests' })); // CORS const cors = require('cors'); app.use(cors({ origin: ['https://myapp.com', 'http://localhost:5173'], methods: ['GET', 'POST', 'PUT', 'DELETE'], credentials: true })); // Helmet — security headers const helmet = require('helmet'); app.use(helmet()); // Route-specific middleware function requireAdmin(req, res, next) { if (req.user?.role !== 'admin') return res.status(403).json({ error: 'Forbidden' }); next(); } router.delete('/:id', requireAdmin, deleteUser);

Building a REST API

Intermediate · 12 min read

// controllers/userController.js const User = require('../models/User'); const getUsers = async (req, res, next) => { try { const { page = 1, limit = 10, sort = '-createdAt' } = req.query; const users = await User .find() .sort(sort) .limit(limit * 1) .skip((page - 1) * limit) .select('-password'); // exclude password const total = await User.countDocuments(); res.json({ users, total, page, pages: Math.ceil(total / limit) }); } catch (err) { next(err); } }; const createUser = async (req, res, next) => { try { const { name, email, password } = req.body; if (!name || !email || !password) return res.status(400).json({ error: 'All fields required' }); const exists = await User.findOne({ email }); if (exists) return res.status(409).json({ error: 'Email exists' }); const hashed = await bcrypt.hash(password, 12); const user = await User.create({ name, email, password: hashed }); res.status(201).json({ id: user._id, name: user.name, email: user.email }); } catch (err) { next(err); } }; module.exports = { getUsers, createUser };

Error Handling

Intermediate · 8 min read

// middleware/errorHandler.js function errorHandler(err, req, res, next) { console.error(err.stack); const status = err.statusCode || 500; const message = err.message || 'Internal Server Error'; // Mongoose validation error if (err.name === 'ValidationError') { return res.status(400).json({ error: Object.values(err.errors).map(e => e.message) }); } // Mongoose duplicate key if (err.code === 11000) { return res.status(409).json({ error: 'Duplicate value' }); } // JWT errors if (err.name === 'JsonWebTokenError') { return res.status(401).json({ error: 'Invalid token' }); } res.status(status).json({ error: message }); } // app.js — register LAST app.use(errorHandler); // 404 handler app.use((req, res) => res.status(404).json({ error: 'Route not found' })); // Async wrapper to avoid try/catch everywhere const asyncHandler = fn => (req, res, next) => Promise.resolve(fn(req, res, next)).catch(next); router.get('/:id', asyncHandler(async (req, res) => { const user = await User.findById(req.params.id); res.json(user); }));

MongoDB with Mongoose

Intermediate · 12 min read

npm install mongoose // config/db.js const mongoose = require('mongoose'); module.exports = async () => { await mongoose.connect(process.env.MONGO_URI, { useNewUrlParser: true, useUnifiedTopology: true }); console.log('MongoDB connected'); }; // models/User.js const { Schema, model } = require('mongoose'); const userSchema = new Schema({ name: { type: String, required: true, trim: true, maxlength: 50 }, email: { type: String, required: true, unique: true, lowercase: true }, password: { type: String, required: true, select: false }, role: { type: String, enum: ['user', 'admin'], default: 'user' }, avatar: String, active: { type: Boolean, default: true } }, { timestamps: true // adds createdAt, updatedAt }); // Virtual field userSchema.virtual('fullName').get(function() { return `${this.firstName} ${this.lastName}`; }); // Pre-save middleware userSchema.pre('save', async function(next) { if (this.isModified('password')) this.password = await bcrypt.hash(this.password, 12); next(); }); // Instance method userSchema.methods.comparePassword = async function(candidate) { return bcrypt.compare(candidate, this.password); }; module.exports = model('User', userSchema);

JWT Authentication

Intermediate · 12 min read

npm install jsonwebtoken bcryptjs // auth controller const jwt = require('jsonwebtoken'); const bcrypt = require('bcryptjs'); const login = async (req, res) => { const { email, password } = req.body; const user = await User.findOne({ email }).select('+password'); if (!user || !await bcrypt.compare(password, user.password)) return res.status(401).json({ error: 'Invalid credentials' }); const token = jwt.sign( { id: user._id, role: user.role }, process.env.JWT_SECRET, { expiresIn: '7d' } ); res.json({ token, user: { id: user._id, name: user.name } }); }; // middleware/auth.js const protect = async (req, res, next) => { const auth = req.headers.authorization; if (!auth?.startsWith('Bearer ')) return res.status(401).json({ error: 'No token' }); try { const decoded = jwt.verify(auth.split(' ')[1], process.env.JWT_SECRET); req.user = await User.findById(decoded.id).select('-password'); next(); } catch (err) { res.status(401).json({ error: 'Token invalid or expired' }); } }; // Usage: protect route router.get('/profile', protect, getProfile);

File Uploads (Multer)

Intermediate · 8 min read

npm install multer const multer = require('multer'); const path = require('path'); const crypto = require('crypto'); // Storage config — save to disk const storage = multer.diskStorage({ destination: (req, file, cb) => cb(null, 'uploads/'), filename: (req, file, cb) => { const ext = path.extname(file.originalname); const unique = crypto.randomUUID(); cb(null, `${unique}${ext}`); } }); // File filter — whitelist allowed types const fileFilter = (req, file, cb) => { const allowed = ['image/jpeg', 'image/png', 'image/webp']; if (allowed.includes(file.mimetype)) cb(null, true); else cb(new Error('Only images allowed'), false); }; const upload = multer({ storage, fileFilter, limits: { fileSize: 5 * 1024 * 1024 } // 5MB }); // Single file router.post('/avatar', protect, upload.single('avatar'), async (req, res) => { const url = `/uploads/${req.file.filename}`; await User.findByIdAndUpdate(req.user.id, { avatar: url }); res.json({ url }); }); // Multiple files router.post('/gallery', upload.array('images', 10), (req, res) => { const urls = req.files.map(f => `/uploads/${f.filename}`); res.json({ urls }); });

Environment Variables

Intermediate · 7 min read

npm install dotenv # .env (NEVER commit this to git) NODE_ENV=development PORT=3000 MONGO_URI=mongodb://localhost:27017/myapp JWT_SECRET=super_secret_key_change_in_prod REDIS_URL=redis://localhost:6379 CORS_ORIGIN=http://localhost:5173 // Load at very top of index.js require('dotenv').config(); // config/index.js — centralize config module.exports = { port: process.env.PORT || 3000, mongoUri: process.env.MONGO_URI, jwtSecret: process.env.JWT_SECRET, nodeEnv: process.env.NODE_ENV || 'development', isDev: process.env.NODE_ENV !== 'production', corsOrigin: process.env.CORS_ORIGIN?.split(',') }; # .env.example (commit this as documentation) NODE_ENV=development PORT=3000 MONGO_URI=mongodb://localhost:27017/myapp JWT_SECRET=your_jwt_secret_here # .gitignore — always ignore .env files .env .env.local .env.production

WebSockets (Socket.io)

Advanced · 10 min read

npm install socket.io // server: src/index.js const http = require('http'); const { Server } = require('socket.io'); const server = http.createServer(app); const io = new Server(server, { cors: { origin: process.env.CORS_ORIGIN } }); // Middleware: authenticate socket connections io.use(async (socket, next) => { const token = socket.handshake.auth.token; try { socket.user = jwt.verify(token, process.env.JWT_SECRET); next(); } catch (e) { next(new Error('Authentication error')); } }); io.on('connection', (socket) => { console.log(`User connected: ${socket.user.id}`); socket.join(`user:${socket.user.id}`); // private room socket.on('message:send', ({ roomId, text }) => { io.to(roomId).emit('message:new', { text, sender: socket.user.id, time: new Date() }); }); socket.on('disconnect', () => console.log('User left')); }); // Client-side import { io } from 'socket.io-client'; const socket = io('http://localhost:3000', { auth: { token: localStorage.getItem('token') } }); socket.emit('message:send', { roomId: 'room1', text: 'Hello!' }); socket.on('message:new', (msg) => console.log(msg));

Clustering & Worker Threads

Advanced · 10 min read

const cluster = require('cluster'); const os = require('os'); // Cluster: spawn one worker per CPU core if (cluster.isPrimary) { const numCPUs = os.cpus().length; console.log(`Primary ${process.pid}: forking ${numCPUs} workers`); for (let i = 0; i < numCPUs; i++) cluster.fork(); cluster.on('exit', (worker, code, signal) => { console.log(`Worker ${worker.pid} died. Forking replacement.`); cluster.fork(); // auto-restart }); } else { startServer(); // each worker runs the Express app } // Worker Threads: CPU-intensive tasks const { Worker, isMainThread, parentPort } = require('worker_threads'); if (isMainThread) { const worker = new Worker(__filename, { workerData: { n: 40 } }); worker.on('message', result => console.log('fib(40) =', result)); } else { const { workerData } = require('worker_threads'); function fib(n) { return n < 2 ? n : fib(n-1) + fib(n-2); } parentPort.postMessage(fib(workerData.n)); }

Deployment with PM2

Advanced · 8 min read

# Install PM2 globally npm install -g pm2 # Start app pm2 start src/index.js --name my-api # Cluster mode (one process per CPU) pm2 start src/index.js -i max --name my-api # ecosystem.config.js — recommended module.exports = { apps: [{ name: 'my-api', script: 'src/index.js', instances: 'max', exec_mode: 'cluster', watch: false, env: { NODE_ENV: 'production', PORT: 3000 }, max_memory_restart: '500M', error_file: 'logs/err.log', out_file: 'logs/out.log' }] }; pm2 start ecosystem.config.js # PM2 commands pm2 list # show all processes pm2 logs my-api # tail logs pm2 restart my-api # restart pm2 reload my-api # zero-downtime reload pm2 stop my-api # stop pm2 delete my-api # remove pm2 monit # live dashboard pm2 startup # auto-start on server reboot pm2 save # save process list