Skip to content

CommonJS Modules

Every Node.js application is made up of modules — files that export functionality and import it from other files. Before ES Modules arrived in Node.js, CommonJS was the only module system. You’ll encounter it constantly in the Node.js ecosystem.

A module is any .js or .ts file. By default, everything in a file is private — variables, functions, classes. You explicitly choose what to expose.

To make something available to other files, assign it to module.exports:

math.js
function add(a, b) {
return a + b
}
function subtract(a, b) {
return a - b
}
module.exports = { add, subtract }

To use exports from another file, call require() with the file path:

index.js
const { add, subtract } = require('./math')
console.log(add(2, 3)) // 5
console.log(subtract(10, 4)) // 6

The ./ prefix means “relative to the current file.” Without it, Node.js looks in node_modules.

When you require('something'), Node.js checks in this order:

  1. Built-in modules (fs, path, http) — no file needed
  2. Relative paths (./math, ../utils) — looks for the exact file
  3. node_modules — looks for a package with that name
const fs = require('fs') // built-in
const math = require('./math') // relative file
const express = require('express') // from node_modules

Node.js wraps every module in a function before executing it:

(function(exports, require, module, __filename, __dirname) {
// your module code runs here
})

This is why __filename (the current file’s path) and __dirname (the current file’s directory) are available in any CommonJS module — they’re injected as arguments. It’s also why require is available without importing it.

You can export a single value as the entire module.exports:

greet.js
module.exports = function greet(name) {
return `Hello, ${name}!`
}
index.js
const greet = require('./greet')
console.log(greet('Alice')) // Hello, Alice!

Many npm packages still ship CommonJS. You’ll see it in:

  • Older Node.js tutorials and codebases
  • Some npm packages (check their package.json for "main" field)
  • Configuration files like eslint.config.cjs

The Bulletin API uses ES Modules (next lesson), but understanding CJS helps when you hit require in the wild.

  1. Create src/utils/math.ts that exports add, subtract, and multiply functions.
  2. Create src/test.ts that requires the math module and logs results of each function.
  3. Run with tsx src/test.ts and verify the output.
  • module.exports makes values available to other files.
  • require('./path') imports those values.
  • Module resolution: built-ins → relative paths → node_modules.
  • __filename and __dirname are injected by Node.js’s module wrapper.
  • CommonJS is still common in the ecosystem even though ES Modules are now preferred.