█
LastWrite
  • > Curriculum
  • > Pricing
  • > For Educators
  • > About
  • > Contact
Log InGet Started

Questions, concerns, bug reports, or suggestions? We read every message, write to us at [email protected].

More ways to reach us →
LastWrite

Structured computer science lessons for aspiring developers and security professionals.

[email protected]

(201) 785-7951

Mon–Fri, 9 AM–5 PM EST

Learn

  • Curriculum
  • Pricing

Company

  • About
  • For Educators & Schools
  • Contact Us

Legal

  • Terms of Service
  • Privacy Policy
© 2026 LastWrite. All rights reserved.
Curriculum/Programming Languages/JavaScript (Standalone Deep Dive)/Modules: ESM vs CommonJS
40 minIntermediate

Modules: ESM vs CommonJS

After this lesson, you will be able to: Skim Node.js core: the event loop in Node, core modules (fs, http, stream, crypto), and what makes Node good at I/O.

Full Node.js depth lives in the pl-node sub-track. This lesson gives the overview from the JS-dev perspective.

Prerequisites:JavaScript Runtimes

Why Node exists

Ryan Dahl (2009) wanted a non-blocking I/O server. V8 + libuv (async I/O library) + a JS API = Node. Single-threaded event loop runs JS; libuv thread pool handles blocking I/O (file system, DNS). Excellent for I/O-heavy workloads (servers, proxies, build tools). Mediocre for CPU-heavy (use worker_threads or spawn other processes).

Core modules every Node dev uses

Available without npm install.

python
import { readFile, writeFile } from "node:fs/promises";
import path from "node:path";
import { createHash, randomBytes } from "node:crypto";
import { fileURLToPath } from "node:url";
import os from "node:os";
// Read a file (async)
const data = await readFile("data.json", "utf-8");
// Get the directory of the current module (ESM equivalent of __dirname)
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
// Hash
const hash = createHash("sha256").update("hello").digest("hex");
// Random bytes
const token = randomBytes(32).toString("hex");
// System info
console.log(os.platform(), os.cpus().length);

Streams: Node's killer feature

Pipe data without buffering everything in memory.

python
import { createReadStream, createWriteStream } from "node:fs";
import { createGzip } from "node:zlib";
import { pipeline } from "node:stream/promises";
// Compress a 1GB file without buffering it
await pipeline(
createReadStream("huge.txt"),
createGzip(),
createWriteStream("huge.txt.gz"),
);
// Streams = HTTP, file I/O, compression, encryption, composable building blocks.

Common mistakes only experienced Node devs avoid

Reading huge files with readFile (loads entire file into memory). Use createReadStream for anything > a few MB. Blocking the event loop with sync APIs (readFileSync, JSON.parse on huge strings). Workers or worker_threads. Skipping `node:` prefix on imports. Modern Node prefers `node:fs` over `fs`. Forgetting that fs.promises is the modern async API; old `fs.readFile(path, callback)` is callback-style.

Quick Check

Why use streams over readFile for a 5GB log file?

Pick the practical answer.

Sign in and purchase access to unlock this lesson.

Sign in to purchase
←Browser vs Node Runtimes
Back to JavaScript (Standalone Deep Dive)
TypeScript in Depth (Advanced)→