ReviseAlgo Logo

Modules & Bundling

CommonJS — require & module.exports

Master CommonJS module patterns in JavaScript. Learn module.exports, require syntax, caching behaviors, and synchronous module resolution.

Last Updated: July 15, 2026 10 min read

1. Introduction

CommonJS (CJS) is a module format standardized for server-side environments (specifically Node.js). It manages modules using the module.exports object to share code and the require() function to import other files.

2. Why It Matters

CommonJS is the foundation of the Node.js ecosystem. Understanding its synchronous loading mechanics and caching behaviors is key to maintaining Node.js backends and legacy frontend projects that compile using CommonJS.

3. Real-World Analogy

Think of a Warehouse Tool Rental Desk:

  • Synchronous loading (Waiting at the counter): You ask the clerk for a drill (require). The clerk walks to the back room, fetches the drill, and hands it to you. While the clerk is fetching the drill, you stand at the counter waiting, and no other tasks can proceed.
  • Module Export (Placing items in the outgoing bin): When writing code, you place tools inside a designated rental bin (module.exports). Only the tools placed in the bin are accessible to other developers; everything else remains inside your private workspace.

4. CommonJS Syntax

In CommonJS, each file is treated as a private module. You share code by assigning it to the module.exports object:

5. Caching and Evaluation

CommonJS modules are evaluated synchronously and their exports are cached in memory:
Synchronous loading: The code stops executing while the required file is read from the disk and parsed.
Cached Exports: The first time a module is required, its code runs, and the exported object is cached. Subsequent require() calls return the cached object directly instead of running the module code again.

6. Practical Example

This script demonstrates exporting a singleton class instance using CommonJS:

7. Common Mistakes

  • Overwriting module.exports after assigning properties to exports: Using both exports.prop = value and module.exports = newObject can cause confusion. exports is simply a reference that points to module.exports. Overwriting module.exports completely breaks this reference, causing the properties assigned to exports to be ignored.

8. Quick Quiz

Q1: How does require() behave when a module is imported multiple times in the same application?

A) The module is evaluated again for every call

B) The module is evaluated once; subsequent calls return the cached export object

Answer: B — CommonJS caches exported objects in memory. Subsequent require() calls return the cached object directly.

9. Scenario-Based Challenge

The Dynamic Config Switcher:

In a Node.js server, you want to load a configuration module dynamically based on the current environment variable: process.env.NODE_ENV. If the environment is "production", load ./config.prod.js, otherwise load ./config.dev.js. Write this loader logic using require().

10. Debugging Exercise

Explain why this import statement returns an empty object, and how to fix it:

// helper.js
exports = function calculate(a) {
  return a * 2;
};
// app.js
const calc = require('./helper');
console.log(calc(5)); // crashes with TypeError: calc is not a function! Why?
View Solution

Diagnosis: The shortcut variable exports is simply a reference that points to the module.exports object. Reassigning exports = function... overwrites the shortcut variable reference, leaving module.exports as an empty object. The importing file receives the empty object instead of the function.

Fix: Assign the function to module.exports directly to overwrite the exported value correctly:

// helper.js
module.exports = function calculate(a) {
  return a * 2;
};

11. Interview Questions

🟢 Q1: Explain how CommonJS modules are loaded and cached in Node.js.

Answer:
Synchronous Loading: require() loads modules synchronously. The thread blocks while the file is read from the disk and parsed, which is fine for server-side environments but inefficient for client-side applications.
Caching: When a module is loaded, its code runs, and the exported object is cached. Subsequent require() calls return the cached object directly instead of running the code again. This ensures that the module acts as a singleton.

12. Production Considerations

  • Transition to ESM: While CommonJS remains widely used in Node.js, modern projects are moving toward ES Modules (ESM) because it supports static analysis and tree shaking. For new projects, use ESM (using import/export) instead.