Chapter 4 of 17
~12 minCore Modules & Global Objects
Node.js ships with a set of built-in modules for common tasks - files, paths, the OS, cryptography - so you rarely need a third-party package for basics. Alongside them sit a handful of true globals, which are worth using sparingly.
fs - the File System Module
`fs` covers reading, writing, and watching files and directories. Nearly every function has three forms: an asynchronous callback version (`fs.readFile`), a synchronous version that blocks the event loop (`fs.readFileSync`), and, in modern Node.js, a Promise-based version under `fs.promises` (or `require('fs/promises')`). Reach for the sync versions only at startup/config-loading time, never inside a request handler, since they block the entire event loop while they run.
const fs = require('fs'); const fsPromises = require('fs/promises'); // Callback style fs.readFile('config.json', 'utf8', (err, data) => { if (err) throw err; console.log('callback:', JSON.parse(data).name); }); // Sync - blocks the event loop, fine at startup only const raw = fs.readFileSync('config.json', 'utf8'); console.log('sync:', JSON.parse(raw).name); // Promise-based - plays nicely with async/await async function loadConfig() { const data = await fsPromises.readFile('config.json', 'utf8'); console.log('promise:', JSON.parse(data).name); } loadConfig();
path - Working with File Paths Safely
`path` lets you build and manipulate file paths without hardcoding path separators, which differ between Windows (`\`) and POSIX systems (`/`). `path.join()` combines segments and normalizes the result, while `path.resolve()` produces an absolute path anchored at the current working directory (or an earlier absolute segment you pass in).
const path = require('path'); console.log(path.join('data', 'users', 'file.json')); // 'data/users/file.json' (or 'data\\users\\file.json' on Windows) console.log(path.resolve(__dirname, '..', 'config.json')); // an absolute path, one directory above this file console.log(path.extname('report.PDF')); // '.PDF' console.log(path.basename('/a/b/c.txt')); // 'c.txt'
os and crypto
`os` reports information about the machine Node.js is running on - CPU count, total/free memory, platform, home directory - useful for scaling decisions (like sizing a `cluster` worker pool) or diagnostics. `crypto` provides hashing, HMACs, and random-byte generation built directly into Node.js, with no external dependency needed for common security primitives.
const crypto = require('crypto'); const hash = crypto.createHash('sha256').update('my-password').digest('hex'); console.log('sha256:', hash); const token = crypto.randomBytes(16).toString('hex'); console.log('random token:', token);
The global Object and Avoiding Pollution
Node.js has a `global` object analogous to `window` in a browser - anything attached to it is reachable from every module without an explicit `require`. Built-ins like `console`, `process`, `setTimeout`, and `Buffer` are effectively available everywhere without importing them, but they are properties Node.js exposes deliberately, not things you should be adding to casually yourself.
Attaching your own app data to `global` (e.g. `global.currentUser = ...`) creates implicit, hard-to-trace coupling between unrelated files and risks name collisions with other modules or future Node.js globals. Prefer exporting values explicitly from a dedicated module (or a small dependency-injection pattern) so it is obvious where shared state comes from.
Coding challenge
Write a Node.js script that uses os to print the total system memory in GB, uses path to build an absolute path to a "logs/app.log" file relative to the script, and uses crypto to print a random 8-byte hex token.
// Write your solution here
Answer every question below to mark this chapter as complete.
Quiz Yourself
Score: 0/41. What is the key risk of using a synchronous fs function like `fs.readFileSync` inside a live HTTP request handler?
2. Why use `path.join()`/`path.resolve()` instead of manually concatenating strings with "/"?
3. What does `crypto.randomBytes()` give you that `Math.random()` does not?
4. Why is attaching app-specific data directly to the `global` object generally discouraged?