LearnThatStack Ace your next interview

Node.js.
Interview cheat sheet.

Quick reference for Node.js - sectioned for fast scanning. Skim the part you're shaky on, walk in confident.

Backend Development 18-section reference ~13 min read

Summary

Node.js is a JavaScript runtime built on Chrome's V8 engine that enables server-side JavaScript development. This cheatsheet covers core Node.js concepts including the event loop, asynchronous programming patterns, module systems, file system operations, HTTP servers, Express.js framework, database integration, authentication, security best practices, error handling, performance optimization, testing strategies, and common design patterns. Key features include non-blocking I/O, single-threaded event loop, NPM ecosystem, and scalability through clustering and microservices architecture.

1. Node.js Fundamentals

What is Node.js?

  • JavaScript runtime built on Chrome's V8 engine
  • Event-driven, non-blocking I/O model
  • Single-threaded but highly scalable

Global Objects

console.log(__dirname);  // Current directory path
console.log(__filename); // Current file path
console.log(process.env); // Environment variables
console.log(process.argv); // Command line arguments

Process Object

process.exit(0); // Exit with success
process.exit(1); // Exit with error
process.on('uncaughtException', (err) => {
  console.error('Uncaught Exception:', err);
});

2. Module System

CommonJS (Traditional)

// math.js
exports.add = (a, b) => a + b;
module.exports = { multiply: (a, b) => a * b };

// main.js
const math = require('./math');
const { add } = require('./math');

ES Modules (Modern)

// math.mjs
export const add = (a, b) => a + b;
export default function multiply(a, b) { return a * b; }

// main.mjs
import multiply, { add } from './math.mjs';

3. Event Loop & Async Patterns

Event Loop Phases

  1. Timers: setTimeout, setInterval
  2. Pending Callbacks: I/O callbacks
  3. Idle, Prepare: Internal use
  4. Poll: Retrieve new I/O events
  5. Check: setImmediate callbacks
  6. Close Callbacks: socket.on('close')

Callbacks

fs.readFile('file.txt', (err, data) => {
  if (err) return console.error(err);
  console.log(data);
});

Promises

const readFile = (path) => {
  return new Promise((resolve, reject) => {
    fs.readFile(path, (err, data) => {
      if (err) reject(err);
      else resolve(data);
    });
  });
};

Async/Await

async function readFiles() {
  try {
    const data1 = await fs.promises.readFile('file1.txt');
    const data2 = await fs.promises.readFile('file2.txt');
    return [data1, data2];
  } catch (error) {
    console.error(error);
  }
}

Event Emitter

const EventEmitter = require('events');
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter();

myEmitter.on('event', (data) => {
  console.log('Event triggered:', data);
});
myEmitter.emit('event', 'Hello World');

4. File System Operations

Reading Files

// Synchronous
const data = fs.readFileSync('file.txt', 'utf8');

// Asynchronous
fs.readFile('file.txt', 'utf8', (err, data) => {
  if (err) throw err;
  console.log(data);
});

// Promise-based
const data = await fs.promises.readFile('file.txt', 'utf8');

Writing Files

// Write (overwrite)
fs.writeFileSync('file.txt', 'Hello World');

// Append
fs.appendFileSync('file.txt', '\nNew Line');

// Stream for large files
const writeStream = fs.createWriteStream('large.txt');
writeStream.write('chunk of data');
writeStream.end();

5. HTTP/HTTPS Server

Basic HTTP Server

const http = require('http');

const server = http.createServer((req, res) => {
  res.statusCode = 200;
  res.setHeader('Content-Type', 'application/json');
  res.end(JSON.stringify({ message: 'Hello World' }));
});

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

HTTPS Server

const https = require('https');
const fs = require('fs');

const options = {
  key: fs.readFileSync('private-key.pem'),
  cert: fs.readFileSync('certificate.pem')
};

https.createServer(options, (req, res) => {
  res.writeHead(200);
  res.end('Secure Hello World');
}).listen(443);

6. Express.js Essentials

Basic Setup

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

// Middleware
app.use(express.json()); // Parse JSON bodies
app.use(express.urlencoded({ extended: true })); // Parse URL-encoded bodies

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

app.post('/users', (req, res) => {
  const { name, email } = req.body;
  res.status(201).json({ id: 1, name, email });
});

app.listen(3000);

Middleware

// Custom middleware
const logger = (req, res, next) => {
  console.log(`${req.method} ${req.url}`);
  next();
};

app.use(logger);

// Error handling middleware
app.use((err, req, res, next) => {
  console.error(err.stack);
  res.status(500).send('Something broke!');
});

Router

const router = express.Router();

router.get('/users', (req, res) => {
  res.json({ users: [] });
});

router.get('/users/:id', (req, res) => {
  const { id } = req.params;
  res.json({ id, name: 'John' });
});

app.use('/api', router);

7. Database Integration

MongoDB with Mongoose

const mongoose = require('mongoose');

// Connection
mongoose.connect('mongodb://localhost/myapp', {
  useNewUrlParser: true,
  useUnifiedTopology: true
});

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

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

// CRUD Operations
const user = await User.create({ name: 'John', email: 'john@example.com' });
const users = await User.find({ age: { $gte: 18 } });
await User.updateOne({ _id: id }, { name: 'Jane' });
await User.deleteOne({ _id: id });

PostgreSQL with pg

const { Pool } = require('pg');
const pool = new Pool({
  connectionString: process.env.DATABASE_URL,
});

// Query
const result = await pool.query('SELECT * FROM users WHERE id = $1', [userId]);

// Transaction
const client = await pool.connect();
try {
  await client.query('BEGIN');
  await client.query('INSERT INTO users(name) VALUES($1)', ['John']);
  await client.query('COMMIT');
} catch (e) {
  await client.query('ROLLBACK');
  throw e;
} finally {
  client.release();
}

8. Authentication & Security

JWT Authentication

const jwt = require('jsonwebtoken');

// Generate token
const token = jwt.sign(
  { userId: user.id, email: user.email },
  process.env.JWT_SECRET,
  { expiresIn: '1h' }
);

// Verify token middleware
const authMiddleware = (req, res, next) => {
  const token = req.headers.authorization?.split(' ')[1];
  
  if (!token) {
    return res.status(401).json({ error: 'No token provided' });
  }
  
  try {
    const decoded = jwt.verify(token, process.env.JWT_SECRET);
    req.user = decoded;
    next();
  } catch (error) {
    res.status(403).json({ error: 'Invalid token' });
  }
};

Password Hashing with bcrypt

const bcrypt = require('bcrypt');

// Hash password
const saltRounds = 10;
const hashedPassword = await bcrypt.hash(plainPassword, saltRounds);

// Verify password
const isValid = await bcrypt.compare(plainPassword, hashedPassword);

Security Best Practices

const helmet = require('helmet');
const rateLimit = require('express-rate-limit');

// Security headers
app.use(helmet());

// Rate limiting
const limiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15 minutes
  max: 100 // limit each IP to 100 requests per windowMs
});
app.use('/api/', limiter);

// CORS
const cors = require('cors');
app.use(cors({
  origin: 'https://trusted-domain.com',
  credentials: true
}));

9. Error Handling

Try-Catch with Async/Await

const asyncHandler = (fn) => (req, res, next) => {
  Promise.resolve(fn(req, res, next)).catch(next);
};

app.get('/users', asyncHandler(async (req, res) => {
  const users = await User.find();
  res.json(users);
}));

Custom Error Class

class AppError extends Error {
  constructor(message, statusCode) {
    super(message);
    this.statusCode = statusCode;
    this.isOperational = true;
    Error.captureStackTrace(this, this.constructor);
  }
}

// Usage
throw new AppError('User not found', 404);

10. Testing

Unit Testing with Jest

// math.test.js
const { add, multiply } = require('./math');

describe('Math functions', () => {
  test('adds 1 + 2 to equal 3', () => {
    expect(add(1, 2)).toBe(3);
  });
  
  test('multiplies 3 * 4 to equal 12', () => {
    expect(multiply(3, 4)).toBe(12);
  });
});

API Testing with Supertest

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

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

11. Performance Optimization

Clustering

const cluster = require('cluster');
const numCPUs = require('os').cpus().length;

if (cluster.isMaster) {
  for (let i = 0; i < numCPUs; i++) {
    cluster.fork();
  }
  
  cluster.on('exit', (worker) => {
    console.log(`Worker ${worker.process.pid} died`);
    cluster.fork();
  });
} else {
  require('./app');
}

Caching with Redis

const redis = require('redis');
const client = redis.createClient();

// Cache middleware
const cache = (req, res, next) => {
  const { id } = req.params;
  
  client.get(id, (err, data) => {
    if (err) throw err;
    
    if (data !== null) {
      res.json(JSON.parse(data));
    } else {
      next();
    }
  });
};

// Set cache
client.setex(id, 3600, JSON.stringify(data));

Stream Processing

// Process large files efficiently
const readStream = fs.createReadStream('large-file.txt');
const writeStream = fs.createWriteStream('output.txt');

readStream
  .pipe(transform) // Transform stream
  .pipe(writeStream)
  .on('finish', () => console.log('Processing complete'));

12. Common Interview Patterns

Singleton Pattern

class Database {
  constructor() {
    if (Database.instance) {
      return Database.instance;
    }
    this.connection = null;
    Database.instance = this;
  }
  
  connect() {
    this.connection = 'Connected';
    return this.connection;
  }
}

const db1 = new Database();
const db2 = new Database();
console.log(db1 === db2); // true

Factory Pattern

class UserFactory {
  static createUser(type) {
    switch(type) {
      case 'admin':
        return new AdminUser();
      case 'regular':
        return new RegularUser();
      default:
        throw new Error('Invalid user type');
    }
  }
}

Middleware Pattern

const pipeline = (...middlewares) => {
  return (req, res) => {
    const execute = (index) => {
      if (index >= middlewares.length) return;
      
      middlewares[index](req, res, () => execute(index + 1));
    };
    execute(0);
  };
};

13. Key Concepts & Comparisons

Node.js Event Loop Phases Deep Dive

Phase Purpose Executes Next Phase Condition
Timer Execute setTimeout/setInterval callbacks Timer callbacks All expired timers processed
Pending Callbacks Execute I/O callbacks deferred to next loop I/O error callbacks All pending callbacks processed
Idle, Prepare Internal Node.js operations Internal use only Automatic
Poll Fetch new I/O events New I/O callbacks Poll queue empty or limit reached
Check Execute setImmediate callbacks setImmediate callbacks All setImmediate processed
Close Callbacks Execute close event callbacks socket.on('close') All close callbacks processed

Callback vs Promise vs Async/Await

Pattern Syntax Error Handling Readability Use Case
Callback func(callback) Error-first callback Poor (callback hell) Legacy APIs, simple operations
Promise .then().catch() .catch() chain Better Modern async operations
Async/Await async/await try/catch Best Complex async workflows
// Callback Hell
getData((err, data) => {
  if (err) throw err;
  processData(data, (err, result) => {
    if (err) throw err;
    saveResult(result, (err) => {
      if (err) throw err;
      console.log('Done');
    });
  });
});

// Promise Chain
getData()
  .then(data => processData(data))
  .then(result => saveResult(result))
  .then(() => console.log('Done'))
  .catch(err => console.error(err));

// Async/Await
async function workflow() {
  try {
    const data = await getData();
    const result = await processData(data);
    await saveResult(result);
    console.log('Done');
  } catch (err) {
    console.error(err);
  }
}

Module Systems Comparison

System Syntax Loading Use Case Browser Support
CommonJS require/module.exports Synchronous Node.js applications No (requires bundler)
ES Modules import/export Asynchronous Modern applications Yes (modern browsers)
AMD define/require Asynchronous Browser applications Yes (with RequireJS)
UMD Universal format Both Libraries Yes

Stream Types & Use Cases

Stream Type Purpose Example When to Use
Readable Read data source fs.createReadStream() File reading, HTTP requests
Writable Write data destination fs.createWriteStream() File writing, HTTP responses
Duplex Both readable and writable net.Socket Network connections
Transform Modify data as it passes zlib.createGzip() Data transformation

Memory Management Patterns

Issue Cause Prevention Detection
Global Variables Unintentional globals Use strict mode, proper scoping Memory profiling
Closures Retained references Clear references when done Heap snapshots
Event Listeners Uncleaned listeners Remove listeners on cleanup Event listener audit
Timers Forgotten intervals/timeouts Clear timers explicitly Timer tracking
Circular References Objects referencing each other Weak references, manual cleanup Reference analysis

Express.js Middleware Order & Types

Type Order Purpose Example
Application-level 1 Global middleware app.use(express.json())
Router-level 2 Route-specific middleware router.use('/users', auth)
Error-handling Last Handle errors app.use((err, req, res, next) => {})
Built-in Varies Express functionality express.static()
Third-party Varies External functionality helmet(), cors()

Database Integration Patterns

Database Driver/ORM Connection Pattern Use Case
MongoDB Mongoose Connection pooling Document-based applications
PostgreSQL pg, Sequelize Connection pooling Relational applications
Redis redis Connection management Caching, sessions
MySQL mysql2, Sequelize Connection pooling Traditional web applications

Authentication Strategies Comparison

Strategy Security Level Scalability State Use Case
Session-based Medium Limited Stateful Traditional web apps
JWT High High Stateless APIs, SPAs
OAuth 2.0 High High Varies Third-party integration
API Keys Medium High Stateless Service-to-service

Error Handling Strategies

Pattern Implementation Pros Cons Use Case
Try-Catch try/catch blocks Simple, local control Doesn't catch async errors Sync operations
Promise Catch .catch() method Handles promise rejections Chain complexity Promise-based code
Error Middleware Express error handler Centralized handling Global scope Express applications
Domain Domain module Process isolation Deprecated Legacy applications
Process Events process.on('uncaughtException') Last resort handling Application termination Critical error logging

Performance Optimization Techniques

Technique Implementation Impact Trade-offs
Clustering cluster module CPU utilization Memory overhead
Worker Threads worker_threads CPU-intensive tasks Complexity
Caching Redis, in-memory Response time Memory usage
Connection Pooling Database pools Database performance Resource management
Compression compression middleware Bandwidth usage CPU overhead
Load Balancing Reverse proxy Scalability Infrastructure complexity

Testing Pyramid for Node.js

Test Type Scope Speed Cost Tools
Unit Tests Individual functions/modules Fast Low Jest, Mocha
Integration Tests Module interactions Medium Medium Supertest, Chai
E2E Tests Full application flow Slow High Cypress, Puppeteer
Contract Tests API contracts Medium Medium Pact

Security Vulnerabilities & Mitigation

Vulnerability Description Prevention Tools
Injection SQL/NoSQL/Command injection Parameterized queries, validation ESLint security rules
Broken Authentication Weak auth implementation Strong passwords, MFA bcrypt, speakeasy
Sensitive Data Exposure Unencrypted data Encryption, HTTPS helmet, crypto
XXE XML External Entity attacks Disable external entities libxml security settings
Broken Access Control Improper authorization Role-based access JWT, RBAC
Security Misconfiguration Default/weak configurations Security headers, updates helmet, audit tools
XSS Cross-site scripting Input sanitization DOMPurify, CSP
Insecure Deserialization Untrusted data deserialization Validation, signed tokens JSON schema validation
Known Vulnerabilities Outdated dependencies Regular updates npm audit, Snyk
Insufficient Logging Poor monitoring Comprehensive logging Winston, Morgan

Scalability Patterns

Pattern Implementation Benefits Considerations
Horizontal Scaling Multiple instances Better fault tolerance Session management
Vertical Scaling Increase resources Simple implementation Hardware limits
Microservices Service decomposition Independent deployment Network complexity
Load Balancing Distribute requests Better resource utilization Single point of failure
Caching Store frequent data Reduced database load Cache invalidation
Database Sharding Partition data Scale database reads/writes Query complexity

Common Design Patterns in Node.js

Pattern Purpose Implementation Use Case
Singleton Single instance Module caching Database connections
Factory Object creation Factory functions User type creation
Observer Event notification EventEmitter Real-time updates
Middleware Request processing Function chains Express pipeline
Proxy Control access Proxy objects API rate limiting
Adapter Interface compatibility Wrapper functions Third-party integration

Environment & Configuration Management

Approach Implementation Pros Cons
Environment Variables process.env Secure, flexible No type checking
Config Files JSON/YAML files Structured, version controlled Can be committed accidentally
Config Libraries dotenv, config Feature-rich Additional dependency
External Config Consul, etcd Centralized, dynamic Network dependency

14. Best Practices Checklist

✅ Always handle errors (try-catch, error middleware)
✅ Use environment variables for configuration
✅ Implement proper logging (Winston, Morgan)
✅ Add input validation (Joi, express-validator)
✅ Use prepared statements to prevent SQL injection
✅ Implement rate limiting for APIs
✅ Add health check endpoints
✅ Use compression middleware for responses
✅ Enable CORS properly
✅ Keep dependencies updated
✅ Use process managers (PM2) in production
✅ Monitor memory usage and performance

15. Quick Command Reference

# NPM Commands
npm init -y                    # Initialize package.json
npm install express           # Install dependency
npm install -D nodemon        # Install dev dependency
npm audit                     # Check vulnerabilities
npm update                    # Update packages

# Process Management
node app.js                   # Run application
nodemon app.js               # Auto-restart on changes
pm2 start app.js             # Production process manager
pm2 logs                     # View logs
pm2 monit                    # Monitor resources

# Debugging
node --inspect app.js        # Enable Chrome DevTools debugging
console.time('label')        # Performance timing
console.timeEnd('label')

Quick Reference Commands

NPM Package Management

# Project initialization
npm init -y                     # Initialize package.json
npm install                     # Install all dependencies
npm install --production        # Install only production dependencies

# Package installation
npm install express             # Install and save to dependencies
npm install -D nodemon         # Install as dev dependency
npm install -g @nestjs/cli     # Install globally

# Package management
npm list                       # List installed packages
npm outdated                   # Check for outdated packages
npm update                     # Update packages
npm audit                      # Security audit
npm audit fix                  # Fix security issues

Process Management

# Development
node app.js                    # Run application
nodemon app.js                # Auto-restart on changes
npm start                     # Run start script
npm run dev                   # Run development script

# Production (PM2)
pm2 start app.js              # Start with PM2
pm2 start app.js --instances 4 # Start with clustering
pm2 list                      # List running processes
pm2 logs                      # View logs
pm2 monit                     # Monitor resources
pm2 restart app               # Restart application
pm2 stop app                  # Stop application
pm2 delete app                # Delete application

Debugging & Monitoring

# Debugging
node --inspect app.js         # Enable Chrome DevTools debugging
node --inspect-brk app.js     # Debug from start
node --prof app.js            # Enable profiling

# Environment
NODE_ENV=production node app.js  # Set environment
DEBUG=* node app.js              # Enable debug output

Essential Node.js Patterns Summary

1. Event Loop & Async Patterns

  • Master the event loop phases and async programming patterns
  • Understand callbacks, promises, and async/await differences
  • Know when to use each pattern and their trade-offs

2. Module System & Architecture

  • CommonJS vs ES Modules comparison and usage
  • Module patterns and best practices
  • Package.json configuration and dependency management

3. HTTP/Express.js Fundamentals

  • HTTP server creation and middleware patterns
  • Express.js routing, middleware, and error handling
  • Request/response handling and RESTful API design

4. Database Integration

  • MongoDB with Mongoose for document databases
  • PostgreSQL/MySQL with connection pooling
  • Transaction management and query optimization

5. Security & Authentication

  • JWT authentication and authorization patterns
  • Input validation and sanitization
  • Security headers and CORS configuration

6. Error Handling & Testing

  • Comprehensive error handling strategies
  • Unit testing with Jest, integration testing
  • Error monitoring and logging best practices

7. Performance & Scalability

  • Clustering and worker threads for CPU utilization
  • Caching strategies with Redis
  • Memory management and garbage collection

8. Production Deployment

  • Environment configuration and secrets management
  • Process managers (PM2) and container deployment
  • Monitoring, logging, and health checks

Interview Pro Tips:

  1. Explain the Event Loop - Critical for Node.js understanding, know all 6 phases
  2. Know Async Patterns - Demonstrate callback hell → promises → async/await evolution
  3. Understand Streams - Essential for handling large data and memory efficiency
  4. Security First - Always mention security considerations (validation, headers, auth)
  5. Scalability Patterns - Clustering, load balancing, caching, microservices
  6. Testing Strategy - Unit, integration, and E2E testing with proper mocking
  7. Performance Optimization - Memory management, connection pooling, caching
  8. Error Handling - Comprehensive error handling and monitoring strategies
Found this useful? Pass it on.
Pro · $10/mo

The sheet is free. Pro goes deeper.

Pro opens the full question library behind every sheet, every refresher and a monthly AI allowance. One subscription, all formats.

Full question library All refreshers Cancel anytime