This episode dissects the four most commonly used core modules: fs for the file system, path for path manipulation, os for system information, and events for EventEmitter. All examples run directly without installing any package.

One of Node.js's strengths is its core modules — built-in libraries ready to use without installing anything. Of the dozens of modules available, four form the foundation of almost every backend application: fs, path, os, and events.
Episode 3 dissects all four modules. You'll see how to read and write files with fs, compose cross-platform paths with path, read system information with os, and build communication between objects with events. After this episode, you won't be confused anymore when you see require("fs") in production code.
Core modules are loaded exactly like npm packages, except there's no install step. Two syntaxes apply: CommonJS and ES Modules. We'll dissect the ES Modules syntax fully in episode 4; for this episode we use CommonJS:
const fs = require("fs");
const path = require("path");
const os = require("os");
const { EventEmitter } = require("events");
console.log("Empat modul core berhasil dimuat");The pattern const { EventEmitter } = require("events") is destructuring — taking just one named property from a module. This is a common pattern for modules that export many things.
The fs (file system) module is the gateway to the file system: creating folders, reading files, writing files, and even streaming data. Here's the simplest example:
const fs = require("fs");
fs.writeFileSync("catatan.txt", "Belajar Node.js");
const isi = fs.readFileSync("catatan.txt", "utf8");
console.log(isi);fs.writeFileSync("catatan.txt", "Belajar Node.js") creates a file and then readFileSync reads it back with the utf8 encoding. The Sync suffix means a blocking version — safe for scripts, but in episode 5 we'll switch to the asynchronous versions that suit servers better.
To see the contents of a folder and check whether a file exists:
const fs = require("fs");
const daftar = fs.readdirSync(".");
console.log(daftar);
console.log(fs.existsSync("catatan.txt"));fs.readdirSync(".") returns the list of files in the current folder, and existsSync checks whether a path exists. Both functions are often used for validation before file operations.
Operating systems use different path separators — Linux and macOS use /, Windows uses \. The path module removes this difference so your code is portable:
const path = require("path");
console.log(path.join("src", "routes", "api.js"));
console.log(path.extname("server.js"));
console.log(path.basename("/app/src/server.js"));path.join("src", "routes", "api.js") produces src/routes/api.js on Linux and src\routes\api.js on Windows. Meanwhile extname takes the file extension and basename takes the file name from a full path.
When code runs, the working folder can differ from the file's location. Use __dirname and path.resolve to always point at the correct location:
const path = require("path");
console.log(__dirname);
console.log(path.resolve("src", "config.js"));__dirname holds the folder location where this file lives. Combining it with path.join is the standard pattern for reading asset files, such as configuration or templates, without depending on the terminal's working folder.
The os module gives access to operating system and hardware information. Useful for startup logs, monitoring, and deployment scripts:
const os = require("os");
console.log(os.platform());
console.log(os.cpus().length);
console.log(os.totalmem() / 1024 / 1024 / 1024);os.platform() returns the system name, os.cpus().length counts the number of CPU cores — this number determines the worker count for clustering in episode 19 — and totalmem reports total RAM in bytes, which we convert to gigabytes.
The events module provides EventEmitter — a pub/sub pattern that underpins many Node.js APIs, including the HTTP server and streams. You can emit and listen for named events:
const { EventEmitter } = require("events");
const emitter = new EventEmitter();
emitter.on("sapa", (nama) => {
console.log("Halo, " + nama);
});
emitter.emit("sapa", "Arman");emitter.on("sapa", (nama) => ...) registers a listener, then emitter.emit("sapa", "Arman") triggers that event along with its arguments. Imagine using this pattern to tell other components that a file has finished downloading or a database connection has closed.
In a real application, all four modules often work together: os reports resources, path composes the log file location, fs writes the log, and events notifies other modules that a new log is available. Mastering all four means mastering 80 percent of the basic needs of a Node.js backend.
Here's what to take away:
fs manages files and directories; the Sync versions suit scripts.path unifies cross-platform paths safely.__dirname and path.resolve produce reliable absolute paths.os provides platform, CPU, and memory data.events provides EventEmitter for communication between objects.In the next episode, episode 4, we'll discuss CommonJS vs ES Modules — the difference between require and import, the "type": "module" field in package.json, how to mix both systems, and best practices for choosing a module format for new projects. The file I/O and streams foundation will be waiting in episode 5.