How does `require` work? Explain module resolution and caching.
3 minintermediatenodejsrequireresolutioncachingnode_modules
Quick Answer
`require` resolves a specifier to an absolute path (core module → relative/absolute path → walking up `node_modules`), loads and executes the file once, and caches `module.exports` in `require.cache`. Subsequent `require`s of the same resolved path return the cached exports without re-running the file.
Detailed Answer
Answer:
Resolution algorithm (roughly):
- Core module? e.g.
require('fs')→ return the built-in. - Relative/absolute path?
./,../,/→ resolve the file, trying extensions.js,.json,.node, then a directory'sindex.jsor itspackage.jsonmain. - Bare specifier? e.g.
require('express')→ look in./node_modules, then the parent directory'snode_modules, walking up to the filesystem root.
require('fs'); // core
require('./utils'); // ./utils.js or ./utils/index.js
require('lodash'); // node_modules/lodash
Caching:
- After a module runs, its
module.exportsis stored inrequire.cache, keyed by the resolved absolute path. - Every later
requireof that path returns the same object — the module body runs only once.
// counter.js
let count = 0;
module.exports = { inc: () => ++count, get: () => count };
// a.js and b.js both require('./counter') share the SAME instance
This is the basis of the singleton pattern in Node and why module top-level code (like a DB connection) runs a single time.
Cache gotchas:
- Two different resolved paths (e.g., two copies of a package in different
node_modules) are separate cached instances — a common source of "instanceof fails" or "duplicate singleton" bugs. - You can delete
require.cache[resolvedPath]to force a reload (used by some hot-reload tools), but it's rarely a good idea in production.