Loading

Quipoin Menu

Learn • Practice • Grow

node-js / Module Caching
tutorial

Module Caching

Here's a common interview question: "If you require the same module in multiple files, how many times is it loaded?" The answer might surprise you – **only once**! This is because Node.js caches modules after they're first loaded. Understanding this caching behavior is crucial for writing efficient code.

How Module Caching Works

When you `require()` a module for the first time, Node.js:
  1. Loads the file.
  2. Executes the code.
  3. Caches the result.
  4. Returns the cached result on subsequent `require()` calls.

Think of module caching like a library book. The first time you borrow it, you take it home. The next time you want it, you don't go buy a new copy – you just borrow the same book again.

Demonstrating Module Caching

counter.js
let count = 0;

function increment() {
  count++;
  return count;
}

function getCount() {
  return count;
}

console.log('Counter module loaded!');

module.exports = { increment, getCount };

a.js
const counter = require('./counter');

console.log('In a.js, count =', counter.increment());

b.js
const counter = require('./counter');

console.log('In b.js, count =', counter.increment());

main.js
require('./a');
require('./b');

Run `node main.js`:
Counter module loaded!
In a.js, count = 1
In b.js, count = 2

Notice: "Counter module loaded!" printed only once, and the count is shared between a.js and b.js.

Implications of Module Caching

  • Singleton Pattern: Modules act as singletons – you get the same instance everywhere.
  • Shared State: If a module has state (like our counter), that state is shared across all requires.
  • Performance: Caching makes repeated requires fast.

When You Might Want to Avoid Caching

Sometimes you want a fresh instance each time. For example, a database connection pool or a logger with a different context. In such cases, export a **factory function** that creates new instances.
logger-factory.js
class Logger {
  constructor(name) {
    this.name = name;
  }
 
  log(message) {
    console.log(`[${this.name}] ${message}`);
  }
}

<!-- Export a factory function, not the class itself -->
module.exports = (name) => new Logger(name);
app.js
const createLogger = require('./logger-factory');

const logger1 = createLogger('App1');
const logger2 = createLogger('App2');

logger1.log('Hello'); <!-- [App1] Hello -->
logger2.log('World'); <!-- [App2] World -->

Clearing the Cache (Advanced)

You can manually clear a module from the cache, but this is rarely needed:
<!-- Get the module path -->
const modulePath = require.resolve('./counter');

<!-- Delete from cache -->
delete require.cache[modulePath];

<!-- Next require will load fresh -->
const counter = require('./counter');

Two Minute Drill

  • Node.js caches modules after the first `require()`.
  • The same module instance is shared across all files that require it.
  • This creates a singleton pattern and enables shared state.
  • Export factory functions if you need fresh instances each time.
  • Caching improves performance but requires understanding for correct state management.

Need more clarification?

Drop us an email at career@quipoinfotech.com