CommonJS Modules

CommonJS (CJS) is a synchronous JavaScript module system historically used extensively in Node.js. It typically loads modules with `require()` and exposes values through `module.exports`, with semantics that differ from ES modules.

A CommonJS module is normally a JavaScript file whose exported API is assigned to `module.exports` or built through `exports`. Another module loads it with `require()`, which returns the exported value. This makes module boundaries explicit and keeps dependencies local to the file.

CommonJS loading is synchronous: `require()` resolves and loads a dependency as part of the calling code's execution. This model fits the traditional Node.js server runtime, where modules are commonly loaded during startup. It is different from the browser-oriented ES module model, which has standardized static imports and asynchronous-capable module loading.

A key detail is that `exports` is initially a reference to `module.exports`. Adding properties through `exports.foo = ...` therefore adds to the exported object, but assigning `exports = ...` only changes the local variable and does not replace the module's exported value. To export a function, primitive, or another complete value, assign directly to `module.exports`.

CommonJS and ES modules can interoperate in Node.js, but the boundary has specific rules around default exports, named exports, module formats, and how modules are interpreted. Interview answers should distinguish the CommonJS mechanism itself from Node.js's particular interoperability behavior, which can depend on the surrounding module configuration and Node.js version.

Key points

Interview questions

What is the difference between `exports` and `module.exports`?

At the beginning of a CommonJS module, `exports` refers to the same object as `module.exports`. Therefore, `exports.add = add` adds a property to the exported object. However, `exports = add` only reassigns the local `exports` variable, so it does not change what `require()` returns. When replacing the entire exported value, use `module.exports = add`.

How do you export and import a value in CommonJS?

A CommonJS module exposes its API through `module.exports`. Another module loads it with `require()`, and the return value is whatever the required module exports. For example, `module.exports = add` makes `const add = require('./math')` receive the function. An object can also be exported when several functions or values belong to the module.

Why is CommonJS described as synchronous?

A CommonJS `require()` performs module resolution and loading as part of the call, so the caller receives the module's exported value synchronously. Code after the `require()` continues after that dependency has been loaded and evaluated according to the runtime's module-loading behavior. This differs from ES module loading, whose standardized design supports asynchronous module loading. The distinction is especially important when discussing browser modules and startup behavior.

How does CommonJS differ from ES modules?

CommonJS generally uses `require()` and `module.exports`, while ES modules use `import` and `export`. CommonJS dependency loading is synchronous, whereas ES modules have standardized static module structure and asynchronous-capable loading. Their export and import interoperability rules are also different, so converting syntax mechanically does not guarantee identical behavior. In Node.js, the exact boundary behavior can depend on the module format and runtime configuration.