Introduction to Modules
A module is a self-contained unit of code — usually a single file — that hides its internals and exposes only what it chooses. Modules are how Node turns thousands of small files into one coherent program: each file has its own scope, declares its dependencies explicitly, and shares a small public surface. Without them, every variable would collide in one global namespace. This page is the map; the following pages drill into each system.
Why modules exist
Browsers historically loaded scripts into one shared global scope — every var and function from every <script> lived together, fighting over names. Node rejected that from day one: each file is its own module with a private scope. The benefits compound as a project grows:
Encapsulation — a module exposes a deliberate API and hides the rest.
Explicit dependencies — you can see exactly what a file needs at the top.
Reusability — the same module is imported by many files, defined once.
No global pollution — names are local unless you export them (why that matters).
Two module systems in Node
Node supports two module systems, and you will encounter both. Knowing which one a file uses is the first thing to check when an import/require error appears:
CommonJS (CJS) | ES Modules (ESM) | |
|---|---|---|
Import |
|
|
Export |
|
|
Default extension |
|
|
Loading | Synchronous | Asynchronous |
Origin | Node's original system | The JavaScript standard |
Top-level await | No | Yes |
Three kinds of module
Regardless of system, the thing you import comes from one of three places. The specifier string tells Node which:
Kind | Specifier looks like | Example |
|---|---|---|
Core (built-in) | A bare name, often |
|
Third-party | A bare name resolved in |
|
Local | A relative or absolute path |
|
We cover the distinction in depth in Core, Local & Third-Party Modules.
A first taste
math.js — the module
function add(a, b) {
return a + b
}
const PI = 3.14159 // private: never exported, invisible to importers
module.exports = { add }app.js — the consumer
const { add } = require('./math.js')
console.log(add(2, 3)) // 5
// console.log(PI) // ReferenceError — PI never left math.js5
What a module gives you for free
Inside any CommonJS file, Node injects a few variables you never declared — require, module, exports, __dirname, __filename. They are not global; they are parameters of a hidden wrapper function Node wraps every file in. That mechanism — and why __dirname differs per file — is explained in The Module Wrapper Function.