Glossary / CommonJS
CommonJS
CommonJS (CJS) is Node.js's traditional module system, centered on require() and module.exports. Each module executes inside a wrapper function with local variables such as exports, require, module, __filename, and __dirname; its exported value is the module.exports object.
Loading and exports
require() resolves and loads synchronously, then caches the module's exported value by resolved filename. Subsequent requires of the same resolved module generally return the cached object rather than re-executing it. exports is initially an alias to module.exports, so adding properties works, but reassigning exports alone does not change the exported value.
// counter.cjs
let count = 0;
module.exports = { next: () => ++count };
// app.cjs
const counter = require('./counter.cjs');
console.log(counter.next());
CommonJS exports are object values, unlike ESM's live imported bindings. Mutating the exported object is observable by consumers holding that same object, but replacing module.exports after consumers receive it does not update their local reference. Circular require() calls can observe a partially initialized exports object.
Interoperability and package mode
In Node.js, .cjs explicitly selects CommonJS; .js interpretation depends on the nearest package "type" and current Node rules. CommonJS can use dynamic import() to load ESM asynchronously. ESM can import CommonJS, but named-export detection is interoperability behavior with constraints; the reliable CJS export is the default value representing module.exports. Bundlers may transform either format, but transformed semantics can differ from native execution.
Engineering guidance
Do not mix module systems casually within one package. Mark package type explicitly and test both development and production loaders. Keep require() side effects understood because loading executes code synchronously. For libraries supporting both systems, define and test conditional package entry points rather than assuming transpilation creates perfect interoperability.
Interview questions
- What does
require()return? The module'smodule.exportsvalue, commonly cached after first evaluation. - Why does
exports = valuefail to replace exports? It only reassigns the local alias; assignmodule.exports = value. - How do CJS cycles behave? A consumer may receive a partially initialized exports object during recursive loading.
- Can CJS load ESM? Through dynamic
import(), which is asynchronous; nativerequire()support is version- and graph-dependent. - How are CJS exports different from ESM bindings? CJS exposes a value/object; ESM exposes statically linked live bindings.