Phase 1 — Foundations lesson-0004

Node.js Core Modules

Built-in superpowers — no npm install required. These modules ship with every Node.js installation.

The Essential Six

fs

File system — read, write, watch files and directories

path

Cross-platform file path manipulation — join, resolve, extname

http

Raw HTTP server and client — the foundation Express builds on

events

EventEmitter — the pub/sub pattern used throughout Node

stream

Process data in chunks — essential for large files and I/O

os

Operating system info — CPU count, memory, platform, homedir

Hands-On: Each Module in Action

fs
path
http
events
stream
const fs = require('fs/promises'); // promise-based API (prefer this)

// Reading a file
const content = await fs.readFile('./data.json', 'utf-8');
const data = JSON.parse(content);

// Writing a file (creates if not exists, overwrites if exists)
await fs.writeFile('./output.json', JSON.stringify(data, null, 2));

// Appending to a file
await fs.appendFile('./log.txt', `[${new Date().toISOString()}] Event\n`);

// Checking if a file exists
try {
  await fs.access('./config.json');
  console.log('Config exists');
} catch {
  console.log('Config missing — using defaults');
}

// Listing directory contents
const files = await fs.readdir('./src');
console.log(files); // ['index.js', 'routes.js', ...]
const path = require('path');

// Join path segments (OS-aware — uses / on Mac/Linux, \ on Windows)
path.join('/users', 'alice', 'docs');    // '/users/alice/docs'
path.join(__dirname, '../config');        // resolves relative to this file

// Resolve to absolute path
path.resolve('./src/index.js');           // '/home/user/project/src/index.js'

// Decompose a path
path.basename('/home/user/file.txt');     // 'file.txt'
path.dirname('/home/user/file.txt');      // '/home/user'
path.extname('/home/user/file.txt');      // '.txt'

// __dirname = directory of the current file (CommonJS only)
// In ES Modules use: import.meta.dirname
console.log(__dirname);   // e.g. '/home/user/project/src'
console.log(__filename);  // e.g. '/home/user/project/src/index.js'
const http = require('http');

// A minimal JSON API server (what Express wraps for you)
const server = http.createServer((req, res) => {
  // Parse URL and method
  const { url, method } = req;

  // Route: GET /health
  if (url === '/health' && method === 'GET') {
    res.writeHead(200, { 'Content-Type': 'application/json' });
    res.end(JSON.stringify({ status: 'ok' }));
    return;
  }

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

server.listen(3000, () => console.log('Listening on :3000'));

// This routing logic is exactly what Express automates
const { EventEmitter } = require('events');

// EventEmitter is the observer pattern built into Node
// Most Node.js objects (streams, servers) extend it

class OrderService extends EventEmitter {
  placeOrder(order) {
    // Do business logic...
    this.emit('order:placed', order); // fire event with data
  }
}

const orders = new OrderService();

// Subscribe to events — decoupled from the emitter
orders.on('order:placed', (order) => {
  console.log(`Send confirmation email for order ${order.id}`);
});

orders.on('order:placed', (order) => {
  console.log(`Trigger inventory check for order ${order.id}`);
});

orders.placeOrder({ id: 123, item: 'Widget' });
// Both listeners fire
const fs = require('fs');

// Problem: reading a 2GB file with readFile() loads it ALL into RAM
// Solution: streams — process it in small chunks

// Pipe a read stream to a write stream (e.g. copy a large file)
const readable = fs.createReadStream('./huge-file.csv');
const writable = fs.createWriteStream('./output.csv');

readable.pipe(writable);

readable.on('end', () => console.log('Done!'));

// In an Express route, stream a file to the response
app.get('/download', (req, res) => {
  res.setHeader('Content-Type', 'text/csv');
  fs.createReadStream('./report.csv').pipe(res);
  // Data flows to the client chunk-by-chunk — never fully in RAM
});
Why learn core modules before Express?
Express is a thin wrapper around Node's http module. When something goes wrong in Express, you end up reading the Node.js docs. Knowing what's underneath makes you a far better debugger.

The global object

Node.js provides several globals — available without requiring anything:

console.log()          // you know this one
setTimeout(fn, ms)    // schedule a callback after ms milliseconds
setInterval(fn, ms)   // repeat a callback every ms milliseconds
clearTimeout(id)      // cancel a timeout
process.env           // object of environment variables (process.env.PORT)
process.exit(1)       // exit the process (0 = success, non-zero = error)
process.argv          // command-line arguments as an array
__dirname             // absolute path of current file's directory (CommonJS)
__filename            // absolute path of current file (CommonJS)

🧠 Check Your Understanding


Go Deeper

Primary source: Node.js docs — fs module — the reference you'll return to most.

Also read: path module docs — short and worth 10 minutes.

Ask your teacher: "When should I use streams instead of readFile?" or "Explain EventEmitter with a real backend example."