Beginner Node.js Interview Questions and Answers

๐Ÿ“‹ Table of Contents โ–พ
  1. Questions & Answers
  2. 📝 Knowledge Check

🟢 Beginner Node.js Interview Questions

This lesson covers the fundamental Node.js concepts every backend developer must know. Master the event loop, modules, npm, the core built-in modules, callbacks, Promises, async/await, and the file system. These questions mirror what interviewers ask at junior and entry-level Node.js roles.

Questions & Answers

01 What is Node.js and what makes it different from browser JavaScript? ►

Core Node.js is an open-source, cross-platform JavaScript runtime built on Chrome’s V8 JavaScript engine. It allows JavaScript to run outside the browser โ€” on servers, desktops, IoT devices, and command-line tools.

Key differences from browser JavaScript:

  • No DOM or Browser APIs โ€” no window, document, localStorage, or navigator. Node provides different globals: process, Buffer, __dirname, __filename.
  • File system access โ€” Node can read and write files (fs module). Browsers cannot for security reasons.
  • Module system โ€” Node uses CommonJS (require()) or ES Modules (import). Browsers use ES Modules only.
  • Built-in modules โ€” http, fs, path, os, crypto, net, child_process โ€” none of which exist in browsers.
  • Single version โ€” you control the exact Node.js version; browsers vary and need polyfills.
// Node.js only โ€” impossible in a browser
const fs = require('fs');
fs.readFileSync('config.json'); // read a file from disk

// Available in Node only
console.log(process.env.NODE_ENV);  // environment variables
console.log(__dirname);             // current directory path

02 What is the Node.js Event Loop? Give a simple explanation. ►

Core The event loop is the mechanism that allows Node.js to perform non-blocking I/O operations despite JavaScript being single-threaded. It continuously checks for work to do and delegates I/O tasks (file reads, network calls) to the operating system or thread pool, then picks up the results when they are ready.

Simplified lifecycle:

// 1. Synchronous code runs first (call stack)
console.log('A'); // prints A

// 2. Async tasks are offloaded and their callbacks are queued
setTimeout(() => console.log('B'), 0);   // queued โ€” runs after current stack
Promise.resolve().then(() => console.log('C')); // microtask โ€” runs before timers

// 3. Remaining synchronous code runs
console.log('D'); // prints D

// Output order: A โ†’ D โ†’ C โ†’ B
// Microtasks (Promises) drain BEFORE timer callbacks

Event loop phases (in order): Timers (setTimeout, setInterval) โ†’ Pending I/O callbacks โ†’ Idle/Prepare โ†’ Poll (wait for I/O) โ†’ Check (setImmediate) โ†’ Close callbacks. Between each phase, the microtask queue (Promises, queueMicrotask) drains completely.

03 What is npm? What is the difference between dependencies and devDependencies? ►

npm npm (Node Package Manager) is the default package manager for Node.js. It manages project dependencies, scripts, and publishing packages to the npm registry.

# Initialise a project
npm init -y

# Install a runtime dependency (added to "dependencies")
npm install express mongoose

# Install a development-only dependency (added to "devDependencies")
npm install --save-dev jest eslint nodemon typescript

# Install globally (CLI tools, not project-specific)
npm install -g nodemon

# Install exact versions from package-lock.json (CI/CD)
npm ci

dependencies vs devDependencies:

  • dependencies โ€” packages required at runtime in production: express, mongoose, bcryptjs, jsonwebtoken. Installed when running npm install in production.
  • devDependencies โ€” packages only needed during development and testing: jest, eslint, nodemon, typescript. Excluded from production installs (npm install --omit=dev).

Keeping devDependencies separate reduces production deployment size and attack surface.

04 What is the CommonJS module system? How does require() work? ►

Modules CommonJS (CJS) is Node.js’s original module system. Each file is its own module with its own scope. You export values with module.exports and import them with require().

// math.js โ€” exporting
function add(a, b) { return a + b; }
function subtract(a, b) { return a - b; }

module.exports = { add, subtract };     // export an object
// OR: module.exports = add;            // export a single value
// OR: exports.add = add;               // shorthand (same as module.exports.add)

// app.js โ€” importing
const math = require('./math');          // relative path โ€” .js extension optional
console.log(math.add(2, 3));            // 5

const { add, subtract } = require('./math'); // destructuring

// Built-in modules (no path prefix)
const fs   = require('fs');
const path = require('path');
const http = require('http');

// npm packages (no path prefix โ€” resolved from node_modules)
const express = require('express');

require() caching: The first call to require('./module') executes the module and caches the result. All subsequent calls return the same cached exports โ€” modules are singletons. Use delete require.cache[require.resolve('./module')] to bust the cache (rarely needed).

05 What are ES Modules (ESM) in Node.js? How do they differ from CommonJS? ►

Modules ES Modules (ESM) is the official JavaScript module standard, available in Node.js since v12 (stable in v14+). Unlike CommonJS, ESM uses import/export syntax and is statically analysable (enabling tree-shaking).

// Enable ESM: use .mjs extension OR set "type": "module" in package.json

// math.mjs โ€” exporting
export function add(a, b)      { return a + b; }
export function subtract(a, b) { return a - b; }
export default { add, subtract }; // default export

// app.mjs โ€” importing
import { add, subtract } from './math.mjs'; // must include extension in ESM
import math from './math.mjs';              // default import
import * as allMath from './math.mjs';      // namespace import

// Dynamic import (works in both CJS and ESM)
const module = await import('./feature.mjs');

Key differences from CommonJS:

  • Static vs dynamic โ€” ESM imports are resolved at parse time; require() runs at execution time
  • Top-level await โ€” ESM supports await at the top level; CJS does not
  • No __dirname/__filename in ESM โ€” use import.meta.url and fileURLToPath instead
  • File extensions required โ€” ESM import must include the full extension (.js, .mjs)
  • One-way compatibility โ€” ESM can import CJS; CJS cannot require() an ESM module
06 What is a callback function in Node.js? What is callback hell? ►

Async A callback is a function passed as an argument to another function, to be called when an asynchronous operation completes. Node.js uses the error-first callback convention: the first parameter is always an error (or null), the second is the result.

// Error-first callback convention
const fs = require('fs');
fs.readFile('./data.json', 'utf8', (err, data) => {
  if (err) return console.error('Error:', err.message);
  console.log('Data:', data);
});

// Callback hell โ€” deeply nested async operations
getUserById(userId, (err, user) => {
  if (err) return handleError(err);
  getOrdersByUser(user.id, (err, orders) => {
    if (err) return handleError(err);
    getProductDetails(orders[0].productId, (err, product) => {
      if (err) return handleError(err);
      sendConfirmationEmail(user.email, product, (err) => {
        if (err) return handleError(err);
        console.log('Done!'); // deeply nested, hard to read and maintain
      });
    });
  });
});

Solutions to callback hell:

  • Named functions โ€” extract callbacks into named functions
  • Promises โ€” chain .then() calls in a flat structure
  • async/await โ€” write async code that looks synchronous (best approach)
07 What are Promises in Node.js? How do you use them? ►

Async A Promise represents the eventual result of an asynchronous operation. It can be in one of three states: pending, fulfilled (resolved with a value), or rejected (failed with a reason).

// Creating a Promise
const fetchUser = (id) => new Promise((resolve, reject) => {
  db.query('SELECT * FROM users WHERE id = ?', [id], (err, rows) => {
    if (err) reject(err);
    else resolve(rows[0]);
  });
});

// Consuming with .then()/.catch()/.finally()
fetchUser(1)
  .then(user  => console.log('User:', user))
  .catch(err  => console.error('Error:', err.message))
  .finally(() => console.log('Done'));

// Promise combinators
Promise.all([fetchUser(1), fetchUser(2)])          // both must resolve
  .then(([u1, u2]) => console.log(u1, u2));

Promise.allSettled([fetchUser(1), fetchUser(99)])   // all complete (even if rejected)
  .then(results => results.forEach(r => console.log(r.status, r.value || r.reason)));

Promise.race([slowOp(), fastOp()])                  // first to settle wins
  .then(result => console.log('Winner:', result));

Promise.any([failOp(), successOp()])                // first to RESOLVE wins
  .then(result => console.log('First success:', result));

08 What is async/await? How does it relate to Promises? ►

Async async/await is syntactic sugar over Promises that makes asynchronous code look and behave like synchronous code. An async function always returns a Promise. await pauses execution inside the function until the Promise settles.

// Promise chain โ€” working but verbose
function getOrderTotal(userId) {
  return getUser(userId)
    .then(user => getOrders(user.id))
    .then(orders => orders.reduce((sum, o) => sum + o.total, 0))
    .catch(err => { throw new Error('Failed: ' + err.message); });
}

// async/await โ€” same logic, much cleaner
async function getOrderTotal(userId) {
  try {
    const user   = await getUser(userId);       // pauses here
    const orders = await getOrders(user.id);    // pauses here
    return orders.reduce((sum, o) => sum + o.total, 0);
  } catch (err) {
    throw new Error('Failed: ' + err.message);
  }
}

// Parallel execution โ€” don't await sequentially if operations are independent
async function loadDashboard(userId) {
  // โŒ Sequential โ€” total time = user time + orders time + recs time
  // const user   = await getUser(userId);
  // const orders = await getOrders(userId);

  // โœ… Parallel โ€” total time = max(user, orders, recs)
  const [user, orders, recommendations] = await Promise.all([
    getUser(userId),
    getOrders(userId),
    getRecommendations(userId)
  ]);
  return { user, orders, recommendations };
}

09 What is the fs module? How do you read and write files? ►

Core Modules The fs (file system) module provides APIs for interacting with the file system. It has synchronous, callback-based, and Promise-based versions.

const fs   = require('fs');
const fsP  = require('fs/promises'); // Promise-based (Node 14+)
const path = require('path');

// โ”€โ”€ Synchronous (blocks event loop โ€” avoid in servers) โ”€โ”€
const data = fs.readFileSync('./config.json', 'utf8');
fs.writeFileSync('./output.txt', 'Hello World', 'utf8');

// โ”€โ”€ Promise-based (recommended in async code) โ”€โ”€
async function processFile() {
  // Read
  const content = await fsP.readFile('./data.json', 'utf8');
  const parsed  = JSON.parse(content);

  // Write
  await fsP.writeFile('./result.json', JSON.stringify(parsed, null, 2));

  // Append
  await fsP.appendFile('./log.txt', `${new Date().toISOString()} โ€” processed\n`);

  // Check if file/dir exists
  try { await fsP.access('./config.json'); }
  catch { console.log('File not found'); }

  // Read directory contents
  const files = await fsP.readdir('./src');

  // Create directory (recursive = create parent dirs too)
  await fsP.mkdir('./output/reports', { recursive: true });

  // Delete a file
  await fsP.unlink('./temp.txt');

  // File stats
  const stats = await fsP.stat('./data.json');
  console.log(stats.size, stats.mtime);
}

10 What is the path module and why is it important? ►

Core Modules The path module provides utilities for working with file and directory paths. It is essential because path separators differ between operating systems (Windows uses \, POSIX uses /). Using path makes code cross-platform.

const path = require('path');

// Join path segments safely (handles OS differences)
const filePath = path.join(__dirname, 'public', 'images', 'logo.png');
// Linux/Mac: /home/user/app/public/images/logo.png
// Windows:   C:\Users\user\app\public\images\logo.png

// Resolve to absolute path
const abs = path.resolve('config', 'settings.json');
// Returns absolute path from current working directory

// Get directory name
path.dirname('/home/user/app/server.js'); // /home/user/app

// Get file name
path.basename('/home/user/app/server.js');      // server.js
path.basename('/home/user/app/server.js', '.js'); // server (without extension)

// Get extension
path.extname('report.2026.pdf'); // .pdf

// Parse path into components
path.parse('/home/user/app/server.js');
// { root: '/', dir: '/home/user/app', base: 'server.js',
//   ext: '.js', name: 'server' }

// Normalise (resolve . and .. segments)
path.normalize('/home/user/../user/app/./server.js');
// /home/user/app/server.js

Always use path.join(__dirname, ...) to construct absolute paths to files relative to the current module. Never concatenate paths with string operators.

11 What is the http module? How do you create a basic HTTP server? ►

Core Modules The http module is Node’s built-in HTTP server and client. While Express is used in practice, understanding the raw http module shows what Express builds on top of.

const http = require('http');

const server = http.createServer((req, res) => {
  // req โ€” http.IncomingMessage (readable stream)
  console.log(req.method, req.url, req.headers);

  // Parse URL and query string
  const url = new URL(req.url, `http://${req.headers.host}`);
  const id  = url.searchParams.get('id');

  // Route based on method and path
  if (req.method === 'GET' && url.pathname === '/users') {
    res.writeHead(200, { 'Content-Type': 'application/json' });
    res.end(JSON.stringify([{ id: 1, name: 'Alice' }]));
    return;
  }

  if (req.method === 'POST' && url.pathname === '/users') {
    let body = '';
    req.on('data', chunk => body += chunk);
    req.on('end', () => {
      const data = JSON.parse(body);
      res.writeHead(201, { 'Content-Type': 'application/json' });
      res.end(JSON.stringify({ id: 2, ...data }));
    });
    return;
  }

  // 404 fallback
  res.writeHead(404, { 'Content-Type': 'application/json' });
  res.end(JSON.stringify({ error: 'Not found' }));
});

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

12 What is the process object in Node.js? ►

Core The process object is a global object providing information and control over the current Node.js process. It is available everywhere without require().

// Environment
console.log(process.env.NODE_ENV);         // "development" / "production"
console.log(process.env.PORT);             // custom env variable

// Process info
console.log(process.pid);                  // process ID
console.log(process.version);             // Node.js version e.g. "v20.11.0"
console.log(process.platform);            // "linux", "darwin", "win32"
console.log(process.arch);               // "x64", "arm64"

// Working directory
console.log(process.cwd());               // current working directory
process.chdir('/tmp');                     // change working directory

// Memory usage
const mem = process.memoryUsage();
console.log(Math.round(mem.rss / 1024 / 1024) + ' MB RSS');

// Exit
process.exit(0);    // success exit
process.exit(1);    // error exit

// Command-line arguments
// node app.js --port 3000 --env prod
console.log(process.argv); // ['node', 'app.js', '--port', '3000', '--env', 'prod']

// Standard I/O
process.stdout.write('Hello');
process.stderr.write('Error message');
process.stdin.on('data', d => console.log('Input:', d.toString()));

// Signal handlers
process.on('SIGTERM', () => { console.log('Shutting down...'); process.exit(0); });
process.on('uncaughtException', (err) => { console.error(err); process.exit(1); });
process.on('unhandledRejection', (reason) => { console.error(reason); });

13 What is the os module? What information does it provide? ►

Core Modules The os module provides operating system-related utility methods and properties โ€” useful for system monitoring, scaling decisions, and cross-platform compatibility.

const os = require('os');

// CPU information
console.log(os.cpus());          // array of CPU cores with model, speed, times
console.log(os.cpus().length);   // number of CPU cores โ€” use for clustering

// Memory
console.log(os.totalmem());      // total memory in bytes
console.log(os.freemem());       // available free memory in bytes
const freeGB = (os.freemem() / 1024 ** 3).toFixed(2);

// Network interfaces
console.log(os.networkInterfaces()); // all NICs with IP addresses

// System info
console.log(os.hostname());      // machine hostname
console.log(os.platform());      // 'linux', 'darwin', 'win32'
console.log(os.arch());          // 'x64', 'arm64'
console.log(os.release());       // OS version string
console.log(os.uptime());        // system uptime in seconds

// User info
console.log(os.userInfo());      // { username, homedir, shell }
console.log(os.homedir());       // /home/username

// Path separator constants
console.log(os.EOL);             // line ending: '\n' (POSIX) or '\r\n' (Windows)
console.log(os.tmpdir());        // temporary files directory

14 What is the EventEmitter in Node.js? ►

Core EventEmitter is the foundation of Node.js’s event-driven architecture. Most Node.js core objects (streams, HTTP server, child processes) extend EventEmitter. You can create your own emitters to build observable objects.

const EventEmitter = require('events');

// Custom event emitter
class OrderService extends EventEmitter {
  async placeOrder(orderData) {
    const order = await createOrder(orderData);
    this.emit('orderPlaced', order);           // emit an event with data
    this.emit('notification', { type: 'email', to: orderData.email });
    return order;
  }
}

const orders = new OrderService();

// Register listeners
orders.on('orderPlaced', (order) => {
  console.log('New order:', order.id);
  updateInventory(order.items);
});

orders.on('notification', async (note) => {
  await sendEmail(note.to, 'Your order is confirmed!');
});

// One-time listener
orders.once('firstOrder', (order) => console.log('First order ever!'));

// Remove a listener
const handler = (order) => console.log(order);
orders.on('orderPlaced', handler);
orders.off('orderPlaced', handler);           // or: orders.removeListener(...)

// Error event โ€” always handle, otherwise Node throws
orders.on('error', (err) => console.error('Order error:', err));
orders.emit('error', new Error('Payment failed'));

15 What is the Buffer class in Node.js? ►

Core Buffer is a global class for working with binary data โ€” raw bytes โ€” outside the V8 heap. It is used extensively for streams, file I/O, network data, cryptography, and binary protocols.

// Creating Buffers
const buf1 = Buffer.alloc(10);                 // 10 zero-filled bytes
const buf2 = Buffer.alloc(10, 0xff);           // 10 bytes filled with 0xff
const buf3 = Buffer.from('Hello');             // from string (default: UTF-8)
const buf4 = Buffer.from('48656c6c6f', 'hex'); // from hex string
const buf5 = Buffer.from([72, 101, 108, 108, 111]); // from byte array

// Convert to string
console.log(buf3.toString('utf8'));   // "Hello"
console.log(buf3.toString('base64')); // "SGVsbG8="
console.log(buf3.toString('hex'));    // "48656c6c6f"

// Manipulate
buf1.write('Node');       // write string into buffer
console.log(buf1[0]);     // read individual byte

// Copy and slice
const copy = buf3.slice(0, 3);  // Buffer view: "Hel" (shares memory)
const copy2 = buf3.subarray(0, 3); // same as slice (preferred)

// Compare and concatenate
Buffer.compare(buf3, buf4);      // 0 = equal, -1 = before, 1 = after
const merged = Buffer.concat([buf3, Buffer.from(' World')]); // "Hello World"

// Check encoding
Buffer.isEncoding('base64'); // true

16 What are timers in Node.js? What is the difference between setTimeout and setImmediate? ►

Async

// setTimeout โ€” execute after at least N milliseconds
const timer = setTimeout(() => console.log('timeout'), 1000);
clearTimeout(timer); // cancel before firing

// setInterval โ€” execute repeatedly every N milliseconds
const interval = setInterval(() => console.log('tick'), 500);
clearInterval(interval); // stop repeating

// setImmediate โ€” execute in the Check phase, AFTER I/O callbacks, BEFORE timers
setImmediate(() => console.log('immediate'));

// queueMicrotask โ€” highest priority, runs before any macrotask
queueMicrotask(() => console.log('microtask'));

// process.nextTick โ€” runs before ANY other async callback (before microtasks in older docs)
// Technically runs between current operation and next event loop iteration
process.nextTick(() => console.log('nextTick'));

// Execution order within one event loop turn:
// 1. Synchronous code
// 2. process.nextTick callbacks
// 3. Promise microtasks (queueMicrotask)
// 4. setImmediate callbacks (Check phase)
// 5. setTimeout (Timers phase โ€” if delay elapsed)

// setTimeout vs setImmediate order depends on context:
// Outside I/O callback: unpredictable (OS-dependent)
// Inside I/O callback: setImmediate ALWAYS runs before setTimeout(fn, 0)

17 What is the url module? How do you parse URLs in Node.js? ►

Core Modules Modern Node.js uses the WHATWG URL API (globally available as URL and URLSearchParams) โ€” the same API as browsers.

// WHATWG URL API โ€” global in Node.js 10+
const url = new URL('https://example.com:8080/products?category=books&sort=price#top');

console.log(url.href);         // full URL string
console.log(url.protocol);     // "https:"
console.log(url.host);         // "example.com:8080"
console.log(url.hostname);     // "example.com"
console.log(url.port);         // "8080"
console.log(url.pathname);     // "/products"
console.log(url.search);       // "?category=books&sort=price"
console.log(url.hash);         // "#top"
console.log(url.origin);       // "https://example.com:8080"

// URLSearchParams โ€” manipulate query strings
const params = url.searchParams;
console.log(params.get('category'));     // "books"
console.log(params.has('sort'));         // true
params.set('page', '2');
params.append('tag', 'fiction');
params.delete('sort');
console.log(params.toString());         // "category=books&page=2&tag=fiction"

// Relative URL resolution
const base = new URL('https://example.com/products/');
const rel  = new URL('../about', base);
console.log(rel.href); // "https://example.com/about"

18 What is the crypto module? How do you hash passwords? ►

Core Modules The crypto module provides cryptographic functionality: hashing, HMAC, encryption, random bytes, and key derivation. For password hashing, use bcrypt (or Node’s built-in crypto.scrypt / crypto.pbkdf2).

const crypto = require('crypto');

// Hashing (one-way, for integrity โ€” NOT for passwords)
const hash = crypto.createHash('sha256').update('hello').digest('hex');
// 2cf24dba... (deterministic โ€” same input always gives same output)

// HMAC (hash + secret key โ€” for message authentication)
const hmac = crypto.createHmac('sha256', 'secret-key').update('message').digest('hex');

// Secure random bytes (for tokens, salts)
const token = crypto.randomBytes(32).toString('hex'); // 64-char hex string
const uuid  = crypto.randomUUID(); // "550e8400-e29b-41d4-a716-446655440000"

// Password hashing with scrypt (built-in, strong)
async function hashPassword(password) {
  const salt   = crypto.randomBytes(16).toString('hex');
  const hash   = await new Promise((resolve, reject) =>
    crypto.scrypt(password, salt, 64, (err, key) =>
      err ? reject(err) : resolve(key.toString('hex'))
    )
  );
  return `${salt}:${hash}`;
}

async function verifyPassword(password, stored) {
  const [salt, hash] = stored.split(':');
  const keyBuffer = Buffer.from(hash, 'hex');
  const derived = await new Promise((res, rej) =>
    crypto.scrypt(password, salt, 64, (err, k) => err ? rej(err) : res(k))
  );
  return crypto.timingSafeEqual(derived, keyBuffer); // constant-time comparison
}

19 What is the util module? What are its most useful methods? ►

Core Modules The util module provides utility functions useful for debugging, type checking, and working with callbacks.

const util = require('util');

// util.promisify โ€” convert callback-based functions to Promises
const fs        = require('fs');
const readFile  = util.promisify(fs.readFile);
const writeFile = util.promisify(fs.writeFile);
const data = await readFile('./config.json', 'utf8'); // now returns a Promise

// util.callbackify โ€” convert async/Promise functions to callback style
const asyncFn      = async (x) => x * 2;
const callbackFn   = util.callbackify(asyncFn);
callbackFn(5, (err, result) => console.log(result)); // 10

// util.inspect โ€” deep string representation of objects (better than JSON.stringify)
console.log(util.inspect({ a: [1,2,3], b: { c: 'deep' } }, { depth: null, colors: true }));

// util.format โ€” printf-style string formatting
util.format('Hello %s, you are %d years old', 'Alice', 29); // "Hello Alice, you are 29 years old"

// util.isDeepStrictEqual โ€” deep equality check
util.isDeepStrictEqual({ a: 1 }, { a: 1 }); // true
util.isDeepStrictEqual({ a: 1 }, { a: '1' }); // false (strict)

// util.types โ€” type checking
util.types.isAsyncFunction(async () => {});  // true
util.types.isPromise(Promise.resolve());       // true
util.types.isMap(new Map());                   // true

20 How do you handle errors in Node.js? What is the difference between operational and programmer errors? ►

Error Handling

  • Operational errors โ€” expected, recoverable failures that are part of normal operation: file not found, network timeout, invalid user input, database connection failure. Handle gracefully with error messages to the user.
  • Programmer errors โ€” bugs: TypeError: cannot read property of undefined, wrong function arguments, logic errors. These indicate a bug in the code. The process should restart.
// Synchronous error โ€” use try/catch
try {
  const data = JSON.parse(invalidJson); // throws SyntaxError (programmer or operational)
} catch (err) {
  console.error('Parse error:', err.message);
}

// Async error โ€” use try/catch with async/await
async function fetchData(url) {
  try {
    const response = await fetch(url);
    if (!response.ok) throw new Error(`HTTP ${response.status}`); // operational
    return response.json();
  } catch (err) {
    throw err; // re-throw for caller to handle
  }
}

// Custom error classes โ€” distinguish error types
class AppError extends Error {
  constructor(message, statusCode) {
    super(message);
    this.name = 'AppError';
    this.statusCode = statusCode;
    this.isOperational = true;
  }
}
throw new AppError('User not found', 404);

// Global safety nets (last resort โ€” not a substitute for proper handling)
process.on('uncaughtException',  err => { logger.error(err); process.exit(1); });
process.on('unhandledRejection', reason => { logger.error(reason); });

21 What is the package.json scripts field? Give useful examples. ►

npm The scripts field in package.json defines shorthand commands runnable via npm run <script>. Scripts have access to locally installed node_modules/.bin executables โ€” no global install needed.

{
  "scripts": {
    "start":        "node dist/server.js",
    "dev":          "nodemon src/server.js",
    "build":        "tsc",
    "test":         "jest",
    "test:watch":   "jest --watch",
    "test:coverage":"jest --coverage",
    "lint":         "eslint src/**/*.ts",
    "lint:fix":     "eslint src/**/*.ts --fix",
    "format":       "prettier --write src/**/*.ts",
    "db:migrate":   "knex migrate:latest",
    "db:seed":      "knex seed:run",
    "docker:up":    "docker-compose up -d",

    "prestart":     "npm run build",    // runs automatically BEFORE "start"
    "posttest":     "npm run lint"      // runs automatically AFTER "test"
  }
}

// Run scripts:
// npm start            โ†’ "node dist/server.js"
// npm test             โ†’ "jest"
// npm run dev          โ†’ "nodemon src/server.js"
// npm run build        โ†’ "tsc"

// Pass extra arguments:
// npm test -- --testNamePattern="auth"   (the -- separates npm args from script args)

// Run multiple scripts in sequence:
// "build": "tsc && cp -r public dist/"   (runs tsc, then copy if tsc succeeds)
// "build": "tsc; cp -r public dist/"     (runs both regardless)

22 What is the difference between package.json and package-lock.json? ►

npm

  • package.json โ€” human-authored manifest declaring the project’s name, version, scripts, and dependency ranges (e.g., "express": "^4.18.0" โ€” any version โ‰ฅ4.18.0 and <5.0.0). Committed to source control. Shared across the team.
  • package-lock.json โ€” auto-generated by npm. Records the exact resolved version of every package and sub-dependency (e.g., "express": "4.18.3"). Ensures every developer and CI system installs the exact same versions. Must be committed to source control.
# Installs based on package.json ranges (may update patch/minor versions)
npm install

# Installs EXACT versions from package-lock.json (recommended for CI)
npm ci

# Why npm ci for CI/CD:
# - Faster (skips resolution step)
# - Fails if package-lock.json is out of sync with package.json
# - Deletes node_modules first (clean install)
# - Never modifies package-lock.json

The ^ prefix means “compatible with” (allows minor and patch updates). ~ allows only patch updates. No prefix means exact version. In production, consider pinning exact versions or using npm ci to ensure reproducibility.

📝 Knowledge Check

Test your understanding of Node.js fundamentals with these five questions.

🧠 Quiz Question 1 of 5

What is the correct order of execution for the following Node.js code?
console.log('A'); setTimeout(() => console.log('B'), 0); Promise.resolve().then(() => console.log('C')); console.log('D');





🧠 Quiz Question 2 of 5

What is the Node.js error-first callback convention?





🧠 Quiz Question 3 of 5

What does require() caching mean in Node.js CommonJS modules?





🧠 Quiz Question 4 of 5

Which npm command installs the exact dependency versions from package-lock.json and is recommended for CI/CD pipelines?





🧠 Quiz Question 5 of 5

What is the primary advantage of using async/await over raw Promise .then() chains?