๐ฆ Node.js Module System
๐ In Node, every file is its own module.
โ๏ธ Node's module system is CommonJS โ built around
require()andmodule.exports, designed for server-side use.๐ JavaScript also has a native ES Module system (
import/export), mostly used in browsers.โ ๏ธ These are two separate, unrelated systems โ don't mix them up.
๐งช Node does support native ES modules via
.mjsfiles, but it hasn't caught on as the default โ CommonJS is still what you'll use most in Node.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Two module systems</title>
</head>
<body>
<div class="mod-info" id="modinfo">
<style>
.mod-info {
--ink: #1a1a1a;
--ink-soft: #5c5c5c;
--paper: #ffffff;
--paper-alt: #f0ece4;
--accent: #2563eb;
--accent-soft: #e3ebfd;
--line: #ddd6c9;
--display-font: 'Fraunces', Georgia, serif;
--body-font: 'Inter', system-ui, sans-serif;
--mono-font: 'IBM Plex Mono', monospace;
max-width: 880px;
margin: 0 auto;
box-sizing: border-box;
padding: 2rem;
font-family: var(--body-font);
color: var(--ink);
background: var(--paper);
}
.mod-info[data-theme="dark"] {
--ink: #e8e6e1;
--ink-soft: #9a968c;
--paper: #121212;
--paper-alt: #1c212b;
--accent: #5b8def;
--accent-soft: #202942;
--line: #2c313d;
}
.mod-info * { box-sizing: border-box; }
.mod-eyebrow {
font-family: var(--mono-font); font-size: 0.68rem; letter-spacing: 0.14em; text-transform: uppercase;
color: var(--accent); text-align: center; margin: 1.5rem 0 0.3rem;
}
.mod-title {
font-family: var(--display-font); font-size: clamp(1.4rem, 5vw, 1.85rem); text-align: center;
margin: 0 0 1.5rem; letter-spacing: -0.01em;
}
/* ---- one file = one module ---- */
.mod-file-row { display: flex; align-items: center; justify-content: center; gap: 0.6rem; margin-bottom: 2rem; }
.mod-file-icon {
width: 44px; height: 44px; border-radius: 10px; display: flex; align-items: center; justify-content: center;
border: 1px solid var(--line); background: var(--paper-alt);
}
.mod-file-icon svg { width: 20px; height: 20px; color: var(--accent); }
.mod-file-eq { font-size: 1.3rem; color: var(--ink-soft); }
.mod-file-badge {
display: flex; align-items: center; gap: 0.4rem; padding: 0.5rem 0.9rem;
border: 1px solid var(--line); border-radius: 20px; background: var(--paper-alt);
font-weight: 700; font-size: 0.85rem;
}
.mod-file-badge svg { width: 16px; height: 16px; color: var(--accent); }
/* ---- comparison cards ---- */
.mod-compare { display: flex; align-items: stretch; gap: 0.6rem; margin-bottom: 1.6rem; }
.mod-card {
flex: 1; border: 1px solid var(--line); border-radius: 10px; background: var(--paper-alt);
padding: 1.1rem 0.9rem; display: flex; flex-direction: column; align-items: center; gap: 0.6rem;
cursor: pointer; transition: border-color 0.2s, background 0.2s;
}
.mod-card:hover { border-color: var(--accent); }
.mod-card.is-active { border-color: var(--accent); background: var(--accent-soft); }
.mod-card-icon {
width: 44px; height: 44px; border-radius: 10px; display: flex; align-items: center; justify-content: center;
border: 1px solid var(--line); background: var(--paper);
}
.mod-card-icon svg { width: 20px; height: 20px; color: var(--ink-soft); transition: color 0.2s; }
.mod-card.is-active .mod-card-icon svg { color: var(--accent); }
.mod-card-name { font-weight: 700; font-size: 0.88rem; }
.mod-card-code {
width: 100%; background: #1e1e1e; border-radius: 6px; padding: 0.55rem 0.65rem;
font-family: var(--mono-font); font-size: 0.68rem; line-height: 1.6; color: #d4d4d8; white-space: pre;
}
.mod-card-code .k { color: #c678dd; }
.mod-card-code .f { color: #61afef; }
.mod-card-code .s { color: #98c379; }
.mod-card-tag {
font-family: var(--mono-font); font-size: 0.62rem; font-weight: 700; letter-spacing: 0.03em;
color: var(--ink-soft); text-transform: uppercase;
}
.mod-vs {
display: flex; align-items: center; justify-content: center; flex: 0 0 auto;
font-family: var(--mono-font); font-weight: 700; font-size: 0.85rem; color: var(--ink-soft);
}
/* ---- default toggle ---- */
.mod-default-row { display: flex; align-items: center; justify-content: center; gap: 0.7rem; margin-bottom: 0.6rem; }
.mod-default-label { font-size: 0.72rem; color: var(--ink-soft); font-weight: 600; }
.mod-switch {
position: relative; width: 46px; height: 24px; border-radius: 12px; border: 1px solid var(--line);
background: var(--paper-alt); cursor: pointer; flex-shrink: 0;
}
.mod-switch-knob {
position: absolute; top: 2px; left: 2px; width: 18px; height: 18px; border-radius: 50%;
background: var(--accent); transition: transform 0.25s;
}
.mod-switch.is-esm .mod-switch-knob { transform: translateX(22px); }
.mod-default-value { font-family: var(--mono-font); font-weight: 700; font-size: 0.82rem; color: var(--accent); min-width: 78px; }
.mod-note { text-align: center; font-size: 0.76rem; color: var(--ink-soft); min-height: 1.3em; margin-bottom: 2.2rem; }
.mod-note b { color: var(--ink); }
@media (prefers-reduced-motion: reduce) {
.mod-info *, .mod-info *::before, .mod-info *::after { transition-duration: 0.001ms !important; animation-duration: 0.001ms !important; }
}
</style>
<div class="mod-file-row">
<div class="mod-file-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z"/><path d="M14 2v5a1 1 0 0 0 1 1h5"/></svg></div>
<span class="mod-file-eq">=</span>
<div class="mod-file-badge">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12.83 2.18a2 2 0 0 0-1.66 0L2.6 6.08a1 1 0 0 0 0 1.83l8.58 3.91a2 2 0 0 0 1.66 0l8.58-3.9a1 1 0 0 0 0-1.83z"/><path d="M2 12a1 1 0 0 0 .58.91l8.6 3.91a2 2 0 0 0 1.65 0l8.58-3.9A1 1 0 0 0 22 12"/><path d="M2 17a1 1 0 0 0 .58.91l8.6 3.91a2 2 0 0 0 1.65 0l8.58-3.9A1 1 0 0 0 22 17"/></svg>
<span>Module</span>
</div>
</div>
<div class="mod-compare">
<div class="mod-card is-active" id="modCjsCard">
<div class="mod-card-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 19h8"/><path d="m4 17 6-6-6-6"/></svg></div>
<div class="mod-card-name">CommonJS</div>
<div class="mod-card-code"><span class="k">const</span> fs = <span class="f">require</span>(<span class="s">'fs'</span>)
module.<span class="f">exports</span> = fn</div>
<div class="mod-card-tag">Node · server</div>
</div>
<div class="mod-vs">vs</div>
<div class="mod-card" id="modEsmCard">
<div class="mod-card-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20"/><path d="M2 12h20"/></svg></div>
<div class="mod-card-name">ES Modules</div>
<div class="mod-card-code"><span class="k">import</span> fs <span class="k">from</span> <span class="s">'fs'</span>
<span class="k">export default</span> fn</div>
<div class="mod-card-tag">Browsers · mostly</div>
</div>
</div>
<div class="mod-default-row">
<span class="mod-default-label">Node uses by default:</span>
<div class="mod-switch" id="modSwitch"><div class="mod-switch-knob"></div></div>
<span class="mod-default-value" id="modDefaultValue">CommonJS</span>
</div>
<p class="mod-note" id="modNote">Tap ES Modules to see Node’s opt-in path.</p>
</div>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link href="https://fonts.googleapis.com/css2?family=Fraunces:wght@500;600&family=Inter:wght@400;500;600;700&family=IBM+Plex+Mono:wght@400;500&display=swap" rel="stylesheet">
<script>
(function () {
var root = document.getElementById('modinfo');
if (!root) return;
var bodyAttr = document.body.getAttribute('data-darkmode');
var dark;
if (bodyAttr === 'true') dark = true;
else if (bodyAttr === 'false') dark = false;
else {
var match = document.cookie.match(/(?:^|;\s*)darkMode=([^;]+)/);
dark = match ? match[1] === 'true' : false;
}
if (dark) root.setAttribute('data-theme', 'dark');
var cjsCard = root.querySelector('#modCjsCard');
var esmCard = root.querySelector('#modEsmCard');
var toggleSwitch = root.querySelector('#modSwitch');
var defaultValue = root.querySelector('#modDefaultValue');
var note = root.querySelector('#modNote');
function setMode(mode) {
cjsCard.classList.toggle('is-active', mode === 'cjs');
esmCard.classList.toggle('is-active', mode === 'esm');
toggleSwitch.classList.toggle('is-esm', mode === 'esm');
if (mode === 'cjs') {
defaultValue.textContent = 'CommonJS';
note.innerHTML = 'What you\u2019ll use in Node almost all the time.';
} else {
defaultValue.textContent = '.mjs files';
note.innerHTML = 'Node <b>can</b> run ES Modules \u2014 rename the file <b>.mjs</b>. It just hasn\u2019t caught on as the default.';
}
}
cjsCard.addEventListener('click', function () { setMode('cjs'); });
esmCard.addEventListener('click', function () { setMode('esm'); });
toggleSwitch.addEventListener('click', function () {
setMode(toggleSwitch.classList.contains('is-esm') ? 'cjs' : 'esm');
});
})();
</script>
</body>
</html>๐ In Node, every file is its own module.
โ๏ธ Node's module system is CommonJS โ built around
require()andmodule.exports, designed for server-side use.๐ JavaScript also has a native ES Module system (
import/export), mostly used in browsers.โ ๏ธ These are two separate, unrelated systems โ don't mix them up.
๐งช Node does support native ES modules via
.mjsfiles, but it hasn't caught on as the default โ CommonJS is still what you'll use most in Node.
โ Where Does require() Actually Come From?
require isn't part of standard JavaScript โ it's not a global language feature. So how does every file get access to it automatically? Node does 4 things behind the scenes every time require() runs:
๐ Resolve the file path
๐ Wrap the code
โถ๏ธ Execute it
๐พ Cache the result

๐ Step 1: Resolving the Path
When you call require('moduleName'), Node figures out which of 3 categories it falls into:
Type | How Node identifies it | Example |
|---|---|---|
โ๏ธ Core module | Built-in name, no path needed |
|
๐จโ๐ป Your own file | Path starts with |
|
๐ฆ npm package | Not a core module, not a relative path |
|
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>How require() finds your module</title>
</head>
<body>
<div class="req-info" id="reqinfo">
<style>
.req-info {
--ink: #1a1a1a;
--ink-soft: #5c5c5c;
--paper: #ffffff;
--paper-alt: #f0ece4;
--accent: #2563eb;
--accent-soft: #e3ebfd;
--line: #ddd6c9;
--err: #dc2626;
--err-soft: #fbe4e2;
--display-font: 'Fraunces', Georgia, serif;
--body-font: 'Inter', system-ui, sans-serif;
--mono-font: 'IBM Plex Mono', monospace;
max-width: 880px;
margin: 0 auto;
box-sizing: border-box;
padding: 2rem;
font-family: var(--body-font);
color: var(--ink);
background: var(--paper);
}
.req-info[data-theme="dark"] {
--ink: #e8e6e1;
--ink-soft: #9a968c;
--paper: #121212;
--paper-alt: #1c212b;
--accent: #5b8def;
--accent-soft: #202942;
--line: #2c313d;
--err: #f87171;
--err-soft: #3a1f1f;
}
.req-info * { box-sizing: border-box; }
.req-eyebrow {
font-family: var(--mono-font); font-size: 0.68rem; letter-spacing: 0.14em; text-transform: uppercase;
color: var(--accent); text-align: center; margin: 1.5rem 0 0.3rem;
}
.req-title {
font-family: var(--display-font); font-size: clamp(1.4rem, 5vw, 1.8rem); text-align: center;
margin: 0 0 0.5rem; letter-spacing: -0.01em;
}
.req-sub { color: var(--ink-soft); font-size: 0.88rem; text-align: center; margin: 0 0 1.4rem; }
.req-examples { display: flex; justify-content: center; gap: 0.4rem; margin-bottom: 1.5rem; flex-wrap: wrap; }
.req-ex-btn {
font-family: var(--mono-font); font-size: 0.72rem; font-weight: 600; padding: 0.45rem 0.7rem;
border-radius: 6px; border: 1px solid var(--line); background: var(--paper); color: var(--ink-soft); cursor: pointer;
}
.req-ex-btn.is-selected { border-color: var(--accent); background: var(--accent-soft); color: var(--accent); }
.req-rows { display: flex; flex-direction: column; gap: 0.5rem; margin-bottom: 1.3rem; }
.req-row { border: 1px solid var(--line); border-radius: 8px; background: var(--paper-alt); overflow: hidden; transition: opacity 0.2s; }
.req-row.is-dim { opacity: 0.4; }
.req-row-head { display: flex; align-items: center; gap: 0.6rem; padding: 0.65rem 0.8rem; }
.req-row-icon { width: 30px; height: 30px; border-radius: 7px; display: flex; align-items: center; justify-content: center; background: var(--paper); border: 1px solid var(--line); flex-shrink: 0; }
.req-row-icon svg { width: 15px; height: 15px; color: var(--ink-soft); }
.req-row.is-match .req-row-icon { border-color: var(--accent); background: var(--accent-soft); }
.req-row.is-match .req-row-icon svg { color: var(--accent); }
.req-row-title { font-weight: 700; font-size: 0.84rem; }
.req-row-sub { font-size: 0.7rem; color: var(--ink-soft); }
.req-row-status { margin-left: auto; width: 18px; height: 18px; flex-shrink: 0; }
.req-row-status svg { width: 100%; height: 100%; }
.req-detail { max-height: 0; overflow: hidden; transition: max-height 0.3s ease; }
.req-row.is-match .req-detail { max-height: 160px; }
.req-detail-inner { padding: 0 0.8rem 0.8rem; border-top: 1px solid var(--line); margin-top: 0.1rem; }
.req-detail-line { display: flex; align-items: center; gap: 0.4rem; font-family: var(--mono-font); font-size: 0.7rem; padding: 0.3rem 0; color: var(--ink-soft); }
.req-detail-line svg { width: 13px; height: 13px; flex-shrink: 0; }
.req-detail-line.is-ok { color: var(--accent); }
.req-detail-line.is-ok svg { color: var(--accent); }
.req-detail-line.is-no svg { color: var(--ink-soft); }
.req-outcome { text-align: center; font-family: var(--mono-font); font-size: 0.82rem; font-weight: 700; padding: 0.6rem; border-radius: 6px; margin-bottom: 2rem; }
.req-outcome.is-ok { background: var(--accent-soft); color: var(--accent); }
.req-outcome.is-err { background: var(--err-soft); color: var(--err); }
.req-outcome.is-empty { visibility: hidden; }
@media (prefers-reduced-motion: reduce) {
.req-info *, .req-info *::before, .req-info *::after { transition-duration: 0.001ms !important; animation-duration: 0.001ms !important; }
}
</style>
<p class="req-sub">Tap a call and watch Node sort it into one of three buckets.</p>
<div class="req-examples">
<button type="button" class="req-ex-btn" data-ex="core">require('fs')</button>
<button type="button" class="req-ex-btn" data-ex="own">require('./lib/controller')</button>
<button type="button" class="req-ex-btn" data-ex="npm">require('express')</button>
<button type="button" class="req-ex-btn" data-ex="missing">require('not-real')</button>
</div>
<div class="req-rows">
<div class="req-row" data-cat="core">
<div class="req-row-head">
<div class="req-row-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9.671 4.136a2.34 2.34 0 0 1 4.659 0 2.34 2.34 0 0 0 3.319 1.915 2.34 2.34 0 0 1 2.33 4.033 2.34 2.34 0 0 0 0 3.831 2.34 2.34 0 0 1-2.33 4.033 2.34 2.34 0 0 0-3.319 1.915 2.34 2.34 0 0 1-4.659 0 2.34 2.34 0 0 0-3.32-1.915 2.34 2.34 0 0 1-2.33-4.033 2.34 2.34 0 0 0 0-3.831A2.34 2.34 0 0 1 6.35 6.051a2.34 2.34 0 0 0 3.319-1.915"/><circle cx="12" cy="12" r="3"/></svg></div>
<div>
<div class="req-row-title">Core module</div>
<div class="req-row-sub">Built-in name, no path</div>
</div>
<div class="req-row-status"></div>
</div>
<div class="req-detail"><div class="req-detail-inner" id="reqDetailCore"></div></div>
</div>
<div class="req-row" data-cat="own">
<div class="req-row-head">
<div class="req-row-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z"/><path d="M14 2v5a1 1 0 0 0 1 1h5"/></svg></div>
<div>
<div class="req-row-title">Your own file</div>
<div class="req-row-sub">Starts with . or ..</div>
</div>
<div class="req-row-status"></div>
</div>
<div class="req-detail"><div class="req-detail-inner" id="reqDetailOwn"></div></div>
</div>
<div class="req-row" data-cat="npm">
<div class="req-row-head">
<div class="req-row-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 3v6"/><path d="M16.76 3a2 2 0 0 1 1.8 1.1l2.23 4.479a2 2 0 0 1 .21.891V19a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V9.472a2 2 0 0 1 .211-.894L5.45 4.1A2 2 0 0 1 7.24 3z"/><path d="M3.054 9.013h17.893"/></svg></div>
<div>
<div class="req-row-title">npm package</div>
<div class="req-row-sub">Not core, not relative</div>
</div>
<div class="req-row-status"></div>
</div>
<div class="req-detail"><div class="req-detail-inner" id="reqDetailNpm"></div></div>
</div>
</div>
<div class="req-outcome is-empty" id="reqOutcome"> </div>
</div>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link href="https://fonts.googleapis.com/css2?family=Fraunces:wght@500;600&family=Inter:wght@400;500;600;700&family=IBM+Plex+Mono:wght@400;500&display=swap" rel="stylesheet">
<script>
(function () {
var root = document.getElementById('reqinfo');
if (!root) return;
var bodyAttr = document.body.getAttribute('data-darkmode');
var dark;
if (bodyAttr === 'true') dark = true;
else if (bodyAttr === 'false') dark = false;
else {
var match = document.cookie.match(/(?:^|;\s*)darkMode=([^;]+)/);
dark = match ? match[1] === 'true' : false;
}
if (dark) root.setAttribute('data-theme', 'dark');
var exBtns = root.querySelectorAll('.req-ex-btn');
var rows = root.querySelectorAll('.req-row');
var outcome = root.querySelector('#reqOutcome');
var CHECK = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="m20 6-11 11-5-5"/></svg>';
var CROSS = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg>';
var DASH = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M5 12h14"/></svg>';
var scenarios = {
core: {
cat: 'core',
detail: '#reqDetailCore',
lines: [
{ text: 'No lookup needed \u2014 it ships with Node', cls: 'is-ok' }
],
outcome: 'Module loaded', ok: true
},
own: {
cat: 'own',
detail: '#reqDetailOwn',
lines: [
{ text: 'controller.js \u2014 found', cls: 'is-ok' }
],
outcome: 'Module loaded', ok: true
},
npm: {
cat: 'npm',
detail: '#reqDetailNpm',
lines: [
{ text: 'Search node_modules/ \u2014 found', cls: 'is-ok' }
],
outcome: 'Module loaded', ok: true
},
missing: {
cat: 'npm',
detail: '#reqDetailNpm',
lines: [
{ text: 'Search node_modules/ \u2014 not found', cls: 'is-no' }
],
outcome: 'Error: Cannot find module \u2014 app stops', ok: false
}
};
function reset() {
rows.forEach(function (r) {
r.classList.remove('is-match', 'is-dim');
r.querySelector('.req-row-status').innerHTML = '';
});
['#reqDetailCore', '#reqDetailOwn', '#reqDetailNpm'].forEach(function (sel) {
root.querySelector(sel).innerHTML = '';
});
outcome.className = 'req-outcome is-empty';
outcome.textContent = '\u00a0';
}
function run(key) {
var s = scenarios[key];
reset();
rows.forEach(function (r) {
var cat = r.getAttribute('data-cat');
var status = r.querySelector('.req-row-status');
if (cat === s.cat) {
r.classList.add('is-match');
status.innerHTML = CHECK;
status.style.color = 'var(--accent)';
var detailEl = root.querySelector(s.detail);
s.lines.forEach(function (line) {
var div = document.createElement('div');
div.className = 'req-detail-line ' + line.cls;
div.innerHTML = (line.cls === 'is-ok' ? CHECK : DASH) + '<span>' + line.text + '</span>';
detailEl.appendChild(div);
});
} else {
r.classList.add('is-dim');
status.innerHTML = CROSS;
status.style.color = 'var(--ink-soft)';
}
});
outcome.classList.remove('is-empty');
outcome.classList.toggle('is-ok', s.ok);
outcome.classList.toggle('is-err', !s.ok);
outcome.textContent = (s.ok ? '\u2713 ' : '\u2717 ') + s.outcome;
}
exBtns.forEach(function (btn) {
btn.addEventListener('click', function () {
exBtns.forEach(function (b) { b.classList.toggle('is-selected', b === btn); });
run(btn.getAttribute('data-ex'));
});
});
})();
</script>
</body>
</html>โ๏ธ You can drop the
.jsextension โ Node adds it automatically.๐ For your own modules: if
./lib/controllerisn't a file, Node checks for a folder namedcontrollerand loads itsindex.js.๐ฆ For npm packages: Node looks inside
node_modulesto find and load them.โ Can't find the module anywhere? Node throws an error and the app stops.
โ If the module can't be found anywhere โ an error is thrown and the app stops.
๐ Step 2: Wrapping (the actual "magic")
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>The actual magic</title>
</head>
<body>
<div class="wrap-info" id="wrapinfo">
<style>
.wrap-info {
--ink: #1a1a1a;
--ink-soft: #5c5c5c;
--paper: #ffffff;
--paper-alt: #f0ece4;
--accent: #2563eb;
--accent-soft: #e3ebfd;
--line: #ddd6c9;
--err: #dc2626;
--err-soft: #fbe4e2;
--display-font: 'Fraunces', Georgia, serif;
--body-font: 'Inter', system-ui, sans-serif;
--mono-font: 'IBM Plex Mono', monospace;
max-width: 880px;
margin: 0 auto;
box-sizing: border-box;
padding: 2rem;
font-family: var(--body-font);
color: var(--ink);
background: var(--paper);
}
.wrap-info[data-theme="dark"] {
--ink: #e8e6e1;
--ink-soft: #9a968c;
--paper: #121212;
--paper-alt: #1c212b;
--accent: #5b8def;
--accent-soft: #202942;
--line: #2c313d;
--err: #f87171;
--err-soft: #3a1f1f;
}
.wrap-info * { box-sizing: border-box; }
.wr-eyebrow {
font-family: var(--mono-font); font-size: 0.68rem; letter-spacing: 0.14em; text-transform: uppercase;
color: var(--accent); text-align: center; margin: 1.5rem 0 0.3rem;
}
.wr-title {
font-family: var(--display-font); font-size: clamp(1.4rem, 5vw, 1.85rem); text-align: center;
margin: 0 0 0.5rem; letter-spacing: -0.01em;
}
.wr-sub { color: var(--ink-soft); font-size: 0.88rem; text-align: center; margin: 0 0 1.4rem; }
/* ---- wrap code ---- */
.wr-code { background: #1e1e1e; border-radius: 8px; padding: 0.8rem 1rem; margin-bottom: 1rem; font-family: var(--mono-font); font-size: 0.72rem; line-height: 1.7; overflow-x: auto; }
.wr-line-outer { color: #6b7280; max-height: 0; opacity: 0; overflow: hidden; transition: max-height 0.4s ease, opacity 0.35s ease; white-space: pre; }
.wr-code.is-wrapped .wr-line-outer { max-height: 40px; opacity: 1; }
.wr-inner { padding-left: 0; transition: padding-left 0.4s ease; color: #d4d4d8; white-space: pre-line; }
.wr-code.is-wrapped .wr-inner { padding-left: 1.3rem; border-left: 2px solid #333; margin-left: 0.15rem; }
.wr-inner .k { color: #c678dd; }
.wr-inner .f { color: #61afef; }
.wr-controls { display: flex; justify-content: center; margin-bottom: 1.4rem; }
.wr-btn {
font-family: var(--mono-font); font-size: 0.82rem; font-weight: 600; padding: 0.6rem 1.2rem;
border-radius: 5px; border: 1px solid var(--accent); background: var(--accent); color: #fff; cursor: pointer;
}
.wr-btn:disabled { opacity: 0.55; cursor: default; }
/* ---- param chips ---- */
.wr-params-label { text-align: center; font-size: 0.72rem; color: var(--ink-soft); margin-bottom: 0.7rem; opacity: 0; transition: opacity 0.3s; }
.wr-params-label.is-shown { opacity: 1; }
.wr-chips { display: flex; justify-content: center; gap: 0.4rem; flex-wrap: wrap; margin-bottom: 0.6rem; opacity: 0; transition: opacity 0.3s; pointer-events: none; }
.wr-chips.is-shown { opacity: 1; pointer-events: auto; }
.wr-chip {
font-family: var(--mono-font); font-size: 0.72rem; font-weight: 600; padding: 0.4rem 0.65rem;
border-radius: 6px; border: 1px solid var(--line); background: var(--paper-alt); color: var(--ink-soft); cursor: pointer;
}
.wr-chip.is-selected { border-color: var(--accent); background: var(--accent-soft); color: var(--accent); }
.wr-chip-desc { text-align: center; font-size: 0.78rem; color: var(--ink-soft); min-height: 1.3em; margin-bottom: 2.2rem; }
.wr-chip-desc b { color: var(--ink); }
/* ---- isolation demo ---- */
.wr-section-label { text-align: center; font-size: 0.72rem; color: var(--ink-soft); text-transform: uppercase; letter-spacing: 0.05em; font-weight: 700; margin-bottom: 0.8rem; }
.wr-iso-toggle { display: flex; justify-content: center; gap: 0.5rem; margin-bottom: 1.3rem; }
.wr-iso-btn {
font-family: var(--body-font); font-size: 0.8rem; font-weight: 600; padding: 0.45rem 0.85rem;
border-radius: 18px; border: 1px solid var(--line); background: var(--paper); color: var(--ink-soft); cursor: pointer;
}
.wr-iso-btn.is-selected { border-color: var(--accent); background: var(--accent-soft); color: var(--accent); }
.wr-iso-files { display: flex; justify-content: center; gap: 1rem; margin-bottom: 0.8rem; }
.wr-iso-file { flex: 0 0 130px; border: 1px solid var(--line); border-radius: 8px; background: var(--paper-alt); padding: 0.7rem; text-align: center; }
.wr-iso-file-name { font-size: 0.66rem; font-weight: 700; color: var(--ink-soft); margin-bottom: 0.4rem; }
.wr-iso-file-code { font-family: var(--mono-font); font-size: 0.78rem; font-weight: 700; padding: 0.35rem; border-radius: 5px; transition: background 0.25s, color 0.25s, border-color 0.25s; border: 1px dashed transparent; }
.wr-iso-file.is-safe .wr-iso-file-code { border-color: var(--accent); color: var(--accent); background: var(--accent-soft); }
.wr-iso-file.is-danger .wr-iso-file-code { border-color: var(--err); color: var(--err); }
.wr-iso-global {
max-width: 260px; margin: 0 auto; text-align: center; padding: 0.6rem; border-radius: 8px;
border: 1px solid var(--line); background: var(--paper-alt); font-family: var(--mono-font); font-size: 0.76rem; font-weight: 700;
transition: border-color 0.25s, background 0.25s, color 0.25s;
}
.wr-iso-global-label { font-size: 0.62rem; font-weight: 700; color: var(--ink-soft); text-transform: uppercase; letter-spacing: 0.04em; margin-bottom: 0.3rem; }
.wr-iso-global.is-collided { border-color: var(--err); background: var(--err-soft); color: var(--err); }
.wr-iso-global.is-empty-safe { color: var(--accent); }
.wr-iso-note { text-align: center; font-size: 0.8rem; color: var(--ink-soft); margin: 0.9rem 0 2.2rem; min-height: 1.3em; }
.wr-iso-note b { color: var(--ink); }
@media (prefers-reduced-motion: reduce) {
.wrap-info *, .wrap-info *::before, .wrap-info *::after { transition-duration: 0.001ms !important; animation-duration: 0.001ms !important; }
}
</style>
<p class="wr-sub">Node never runs your file directly. It wraps it first.</p>
<div class="wr-code" id="wrCode">
<div class="wr-line-outer">(function (exports, require, module, __filename, __dirname) {</div>
<div class="wr-inner"><span class="k">let</span> x = <span class="k">1</span>;
module.<span class="f">exports</span> = x;</div>
<div class="wr-line-outer">});</div>
</div>
<div class="wr-controls">
<button type="button" class="wr-btn" id="wrWrapBtn">โถ Wrap it</button>
</div>
<p class="wr-params-label" id="wrParamsLabel">Node calls this function, passing in:</p>
<div class="wr-chips" id="wrChips">
<button type="button" class="wr-chip" data-p="exports">exports</button>
<button type="button" class="wr-chip" data-p="require">require</button>
<button type="button" class="wr-chip" data-p="module">module</button>
<button type="button" class="wr-chip" data-p="__filename">__filename</button>
<button type="button" class="wr-chip" data-p="__dirname">__dirname</button>
</div>
<p class="wr-chip-desc" id="wrChipDesc"> </p>
<p class="wr-section-label">Why wrapping matters: isolation</p>
<div class="wr-iso-toggle">
<button type="button" class="wr-iso-btn is-selected" data-iso="without">Without wrapping</button>
<button type="button" class="wr-iso-btn" data-iso="with">With wrapping</button>
</div>
<div class="wr-iso-files">
<div class="wr-iso-file" id="wrFileA">
<div class="wr-iso-file-name">a.js</div>
<div class="wr-iso-file-code">let x = 1</div>
</div>
<div class="wr-iso-file" id="wrFileB">
<div class="wr-iso-file-name">b.js</div>
<div class="wr-iso-file-code">let x = 2</div>
</div>
</div>
<div class="wr-iso-global" id="wrGlobal">
<div class="wr-iso-global-label">Global</div>
<div id="wrGlobalValue">x = 2</div>
</div>
<p class="wr-iso-note" id="wrIsoNote">Both files leak into the same global <b>x</b> \u2014 b.js quietly overwrites a.js.</p>
</div>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link href="https://fonts.googleapis.com/css2?family=Fraunces:wght@500;600&family=Inter:wght@400;500;600;700&family=IBM+Plex+Mono:wght@400;500&display=swap" rel="stylesheet">
<script>
(function () {
var root = document.getElementById('wrapinfo');
if (!root) return;
var bodyAttr = document.body.getAttribute('data-darkmode');
var dark;
if (bodyAttr === 'true') dark = true;
else if (bodyAttr === 'false') dark = false;
else {
var match = document.cookie.match(/(?:^|;\s*)darkMode=([^;]+)/);
dark = match ? match[1] === 'true' : false;
}
if (dark) root.setAttribute('data-theme', 'dark');
/* ---- wrap animation ---- */
var wrapBtn = root.querySelector('#wrWrapBtn');
var codeBlock = root.querySelector('#wrCode');
var paramsLabel = root.querySelector('#wrParamsLabel');
var chipsRow = root.querySelector('#wrChips');
var chipDesc = root.querySelector('#wrChipDesc');
var chips = root.querySelectorAll('.wr-chip');
var descriptions = {
exports: 'A shortcut that points to <b>module.exports</b>.',
require: 'Imports other modules.',
module: 'A reference to this module \u2014 mainly used to export data via <b>module.exports</b>.',
__filename: 'Absolute path to the current file.',
__dirname: 'Absolute path to the current file\u2019s folder.'
};
wrapBtn.addEventListener('click', function () {
if (codeBlock.classList.contains('is-wrapped')) return;
codeBlock.classList.add('is-wrapped');
wrapBtn.disabled = true;
wrapBtn.textContent = '\u2713 Wrapped';
setTimeout(function () {
paramsLabel.classList.add('is-shown');
chipsRow.classList.add('is-shown');
}, 450);
});
chips.forEach(function (chip) {
chip.addEventListener('click', function () {
chips.forEach(function (c) { c.classList.toggle('is-selected', c === chip); });
var p = chip.getAttribute('data-p');
chipDesc.innerHTML = '<b>' + p + '</b> \u2014 ' + descriptions[p];
});
});
/* ---- isolation toggle ---- */
var isoBtns = root.querySelectorAll('.wr-iso-btn');
var fileA = root.querySelector('#wrFileA');
var fileB = root.querySelector('#wrFileB');
var globalBox = root.querySelector('#wrGlobal');
var globalValue = root.querySelector('#wrGlobalValue');
var isoNote = root.querySelector('#wrIsoNote');
function setIso(mode) {
isoBtns.forEach(function (b) { b.classList.toggle('is-selected', b.getAttribute('data-iso') === mode); });
if (mode === 'without') {
fileA.classList.remove('is-safe'); fileA.classList.add('is-danger');
fileB.classList.remove('is-safe'); fileB.classList.add('is-danger');
globalBox.classList.add('is-collided'); globalBox.classList.remove('is-empty-safe');
globalValue.textContent = 'x = 2';
isoNote.innerHTML = 'Both files leak into the same global <b>x</b> \u2014 b.js quietly overwrites a.js.';
} else {
fileA.classList.add('is-safe'); fileA.classList.remove('is-danger');
fileB.classList.add('is-safe'); fileB.classList.remove('is-danger');
globalBox.classList.remove('is-collided'); globalBox.classList.add('is-empty-safe');
globalValue.textContent = '(untouched)';
isoNote.innerHTML = 'Each <b>x</b> lives inside its own wrapper function \u2014 nothing reaches the global object.';
}
}
isoBtns.forEach(function (btn) {
btn.addEventListener('click', function () { setIso(btn.getAttribute('data-iso')); });
});
setIso('without');
})();
</script>
</body>
</html>This step explains why require, module, etc. just exist in every file without you importing them.
Node never runs your file's code directly. Instead, it wraps it inside a function โ specifically an IIFE (a function that runs immediately):
(function (exports, require, module, __filename, __dirname) {
// your code goes here
});Node then calls this wrapper, passing in 5 values as arguments:
๐ค
exports๐ฅ
require๐ฆ
module๐
__filename๐
__dirname
That's the whole trick โ these aren't global variables, they're just function parameters your code happens to receive automatically.
๐ก Two reasons this wrapping matters
โ Access โ every module gets
require,module,__filename,__dirnamefor free, injected as arguments.๐ Isolation โ top-level variables stay scoped to that file instead of leaking into the global object. Without this, if you declared
let xand some npm package also had its own top-levelx, they could collide and overwrite each other. Wrapping keeps each file's variables private to itself.
๐ What each injected value is
๐ฅ
requireโ imports other modules๐ฆ
moduleโ reference to this module; mainly used to export data viamodule.exports๐ค
exportsโ a shortcut that points tomodule.exports๐
__filenameโ absolute path to the current file๐
__dirnameโ absolute path to the current file's folder
โถ๏ธ Step 3: Execution
Once wrapped, the module's code (inside that wrapper function) is simply executed by the Node runtime. Nothing special here โ just normal code execution at this point.
๐ค Step 4: What require() Returns
After execution, require() hands back whatever was assigned to module.exports.
๐ ฐ๏ธ Exporting one thing (a single class/function/value):
module.exports = SomeClassOrFunction;๐ ฑ๏ธ Exporting multiple named things:
exports.add = (a, b) => a + b;
exports.multiply = (a, b) => a * b;
exports.divide = (a, b) => a / b;๐ฆ One export โ
module.exports = ...๐ท๏ธ Multiple exports โ
exports.name = ...๐ก This is why you always assign
require()'s result to a variable โ you're capturing whatever got exported.
๐พ Step 5: Caching
The first time a module is required, Node runs it and caches the result.
Every later
require()of that same module returns the cached result โ the file's code does not run again.This means module-level code executes exactly once per app, no matter how many files require it.
โ Key Takeaway
Every require() call goes through the same pipeline:
๐ Resolve โ figure out if it's core / your file / npm, and locate it
๐ Wrap โ inject
exports,require,module,__filename,__dirnamevia a wrapper functionโถ๏ธ Execute โ run the wrapped code normally
๐ค Return โ hand back
module.exports๐พ Cache โ store the result so future
require()calls skip re-running the code