390

From the node.js documentation:

Modules are cached after the first time they are loaded. This means (among other things) that every call to require('foo') will get exactly the same object returned, if it would resolve to the same file.

Is there a way to invalidate this cache? i.e. for unit testing, I'd like each test to be working on a fresh object.

William
  • 13,332
  • 13
  • 60
  • 73

18 Answers18

361

You can always safely delete an entry in require.cache without a problem, even when there are circular dependencies. Because when you delete, you just delete a reference to the cached module object, not the module object itself, the module object will not be GCed because in case of circular dependencies, there is still a object referencing this module object.

Suppose you have:

script a.js:

var b=require('./b.js').b;
exports.a='a from a.js';
exports.b=b;

and script b.js:

var a=require('./a.js').a;
exports.b='b from b.js';
exports.a=a;

when you do:

var a=require('./a.js')
var b=require('./b.js')

you will get:

> a
{ a: 'a from a.js', b: 'b from b.js' }
> b
{ b: 'b from b.js', a: undefined }

now if you edit your b.js:

var a=require('./a.js').a;
exports.b='b from b.js. changed value';
exports.a=a;

and do:

delete require.cache[require.resolve('./b.js')]
b=require('./b.js')

you will get:

> a
{ a: 'a from a.js', b: 'b from b.js' }
> b
{ b: 'b from b.js. changed value',
  a: 'a from a.js' }

===

The above is valid if directly running node.js. However, if using tools that have their own module caching system, such as jest, the correct statement would be:

jest.resetModules();
José Cabo
  • 6,149
  • 3
  • 28
  • 39
kaisa1028
  • 3,756
  • 2
  • 15
  • 2
  • 4
    could you please explain why `{ ... a: undefined}` when requiring `b.js` for the first time ? I would expect to equal `'a from a.js'`. Thank you – ira Aug 07 '17 at 07:43
  • 1
    why is a undefined? – Jeff P Chacko Aug 15 '17 at 07:15
  • 6
    Late reply, but from what I gather `b[a]` is undefined the first time since there's a circular dependency. `a.js` requires `b.js` which in turn requires `a.js`. `a.js` is not yet fully loaded and `exports.a` is yet to be defined, so `b.js` get's nothing. – nik10110 Sep 24 '17 at 09:48
  • any way to do this if I'm using `require.main.require(path)` as described here? https://stackoverflow.com/questions/10860244/how-to-make-the-require-in-node-js-to-be-always-relative-to-the-root-folder-of-t – Flion Mar 12 '18 at 17:06
  • 2
    Thank you for adding the last paragraph with 'jest.resetModules();', could be really helpful as most tutorials I came accross used Mocha! – szeb Sep 03 '20 at 17:42
255

If you always want to reload your module, you could add this function:

function requireUncached(module) {
    delete require.cache[require.resolve(module)];
    return require(module);
}

and then use requireUncached('./myModule') instead of require.

luff
  • 3,334
  • 1
  • 18
  • 9
  • 12
    This is perfect in combination with the `fs.watch` method which listens for file changes. – ph3nx Jul 12 '14 at 09:09
  • 4
    what is the risk? – Scarass Nov 11 '18 at 13:31
  • Same question I have, what is the risk of using this solution and not the accepted answer? – rotimi-best Feb 11 '19 at 09:39
  • 4
    It's the same really. Depending on how the code is structured, things might crash when you try to initialize it again. Ex. if the module starts a server, and listens to a port. The next time you requireUncached the module, it will fail since that port is already opened, and so on. – luff Feb 11 '19 at 13:21
  • An almost perfectly elegant solution, except for `delete` which can be _quite_ slow. – user10398534 Sep 15 '20 at 09:55
  • for some reason this causes memory to pile up on each call (I'm using on a server that calls on each request), switching back to normal `require` fixes the memory issue completely – tga Apr 16 '21 at 22:04
  • 5
    it bemuses me that this function isn't called reacquire(), but that's just me. – unsynchronized May 07 '21 at 14:23
  • see my version, https://stackoverflow.com/a/67437133/830899 if you want to abort the reload if the updated version has syntax errors (useful on sites like glitch where editor updates files as you type) – unsynchronized May 07 '21 at 14:50
  • @luff: So what the side effects for the same? – Aniruddha Shevle Apr 20 '22 at 09:16
  • 1
    Why is the module name wrapped by `require.resolve`, and not just `require.cache[module]`? – Wayrex May 25 '22 at 16:08
140

Yes, you can access the cache via require.cache[moduleName] where moduleName is the name of the module you wish to access. Deleting an entry by calling delete require.cache[moduleName] will cause require to load the actual file.

This is how you would remove all cached files associated with the module:

/**
 * Removes a module from the cache
 */
function purgeCache(moduleName) {
    // Traverse the cache looking for the files
    // loaded by the specified module name
    searchCache(moduleName, function (mod) {
        delete require.cache[mod.id];
    });

    // Remove cached paths to the module.
    // Thanks to @bentael for pointing this out.
    Object.keys(module.constructor._pathCache).forEach(function(cacheKey) {
        if (cacheKey.indexOf(moduleName)>0) {
            delete module.constructor._pathCache[cacheKey];
        }
    });
};

/**
 * Traverses the cache to search for all the cached
 * files of the specified module name
 */
function searchCache(moduleName, callback) {
    // Resolve the module identified by the specified name
    var mod = require.resolve(moduleName);

    // Check if the module has been resolved and found within
    // the cache
    if (mod && ((mod = require.cache[mod]) !== undefined)) {
        // Recursively go over the results
        (function traverse(mod) {
            // Go over each of the module's children and
            // traverse them
            mod.children.forEach(function (child) {
                traverse(child);
            });

            // Call the specified callback providing the
            // found cached module
            callback(mod);
        }(mod));
    }
};

Usage would be:

// Load the package
var mypackage = require('./mypackage');

// Purge the package from cache
purgeCache('./mypackage');

Since this code uses the same resolver require does, just specify whatever you would for require.


"Unix was not designed to stop its users from doing stupid things, as that would also stop them from doing clever things." – Doug Gwyn

I think that there should have been a way for performing an explicit uncached module loading.

Ben Barkay
  • 5,473
  • 2
  • 20
  • 29
  • 19
    +1 just for Doug's quote. I needed someone to phrase out what I also believed in :) – Poni Mar 17 '13 at 09:36
  • 1
    Excellent answer! If you would like to start a node repl with reloading enabled check out [this gist](https://gist.github.com/gleitz/6896099). – gleitz Oct 09 '13 at 04:16
  • 2
    awesome. I would add this to the `require.uncache` function. ``` // see https://github.com/joyent/node/issues/8266 Object.keys(module.constructor._pathCache).forEach(function(k) { if (k.indexOf(moduleName)>0) delete module.constructor._pathCache[k]; }); ``` Say you've required a module, then uninstalled it, then reinstalled the same module but used a different version that has a different main script in its package.json, the next require will fail because that main script does not exists because it's cached in `Module._pathCache` – bentael Aug 26 '14 at 20:59
  • crap. my comment is terrible. I couldn't neatly add code in this comment and it's too late to edit, so I answered. @Ben Barkay if you could edit your question to add the little snippet of code to your `require.uncache` – bentael Aug 26 '14 at 21:06
  • Thanks @bentael, I've added this to my answer. – Ben Barkay Aug 28 '14 at 14:43
  • Thanks a lot @bentael for your investigation, but it seems unfortunately not enough. The main script name is kept in cache in the `packageMainCache` property, which is not accessible from outside. If I try to update a package with a dependency where the main file has moved, I now get a `Cannot find module` error. I will comment on yout GitHub issue. – Sylvain B Sep 03 '14 at 10:24
  • On the `Object.keys` line, why not use `for..of` ? – user10398534 Sep 15 '20 at 09:56
47

There's a Simple Module for that (with tests)

We had this exact issue while testing our code (delete cached modules so they can be re-required in a fresh state) so we reviewed all the suggestions of people on the various StackOverflow Questions & Answers and put together a simple node.js module (with tests):

https://www.npmjs.com/package/decache

As you would expect, works for both published npm packages and locally defined modules. Windows, Mac, Linux, etc.

Build Status codecov.io Code Climate maintainability Dependencies Status devDependencies Status

How? (usage)

Usage is pretty simple:

install

Install the module from npm:

npm install decache --save-dev

Use it in your code:

// require the decache module:
const decache = require('decache');

// require a module that you wrote"
let mymod = require('./mymodule.js');

// use your module the way you need to:
console.log(mymod.count()); // 0   (the initial state for our counter is zero)
console.log(mymod.incrementRunCount()); // 1

// delete the cached module:
decache('./mymodule.js');

//
mymod = require('./mymodule.js'); // fresh start
console.log(mymod.count()); // 0   (back to initial state ... zero)

If you have any questions or need more examples, please create a GitHub issue: https://github.com/dwyl/decache/issues

Glorfindel
  • 21,988
  • 13
  • 81
  • 109
nelsonic
  • 31,111
  • 21
  • 89
  • 120
  • 1
    I've been looking at this and it looks really great for me to use when testing so that I can unload and reload a module under specific conditions, but unfortunately I'm at work and my company shies away from GPL licenses. I only want to use it for testing so I am still considering it because it looks so helpful. – Matt_JD Mar 09 '16 at 07:28
  • @Matt_JD thanks for your feedback. which licence would you prefer? – nelsonic Mar 09 '16 at 14:13
  • Work prefers non-copyleft. I thnk most things I've used so far are MIT. I've overcome my current problem by doing var path = require.resolve('module'); delete require.cache[path]; require('module'); Or something like that. – Matt_JD Mar 09 '16 at 18:49
  • 2
    @Matt_JD We've updated the license to MIT. Good luck with your work! :-) – nelsonic Mar 09 '16 at 22:39
  • 1
    this worked amazingly! Starring this repo and upvoting this answer. – aholt Nov 13 '18 at 22:41
  • 1
    highly recommend, running fine on latest v14.2.0 as of today – Thom May 10 '20 at 17:56
31

For anyone coming across this who is using Jest, because Jest does its own module caching, there's a built-in function for this - just make sure jest.resetModules runs eg. after each of your tests:

afterEach( function() {
  jest.resetModules();
});

Found this after trying to use decache like another answer suggested. Thanks to Anthony Garvan.

Function documentation here.

Tim Malone
  • 3,364
  • 5
  • 37
  • 50
19

The solutions is to use:

delete require.cache[require.resolve(<path of your script>)]

Find here some basic explanations for those who, like me, are a bit new in this:

Suppose you have a dummy example.js file in the root of your directory:

exports.message = "hi";
exports.say = function () {
  console.log(message);
}

Then you require() like this:

$ node
> require('./example.js')
{ message: 'hi', say: [Function] }

If you then add a line like this to example.js:

exports.message = "hi";
exports.say = function () {
  console.log(message);
}

exports.farewell = "bye!";      // this line is added later on

And continue in the console, the module is not updated:

> require('./example.js')
{ message: 'hi', say: [Function] }

That's when you can use delete require.cache[require.resolve()] indicated in luff's answer:

> delete require.cache[require.resolve('./example.js')]
true
> require('./example.js')
{ message: 'hi', say: [Function], farewell: 'bye!' }

So the cache is cleaned and the require() captures the content of the file again, loading all the current values.

Community
  • 1
  • 1
fedorqui
  • 275,237
  • 103
  • 548
  • 598
5

rewire is great for this use case, you get a new instance with each call. Easy dependency injection for node.js unit testing.

rewire adds a special setter and getter to modules so you can modify their behaviour for better unit testing. You may

inject mocks for other modules or globals like process leak private variables override variables within the module. rewire does not load the file and eval the contents to emulate node's require mechanism. In fact it uses node's own require to load the module. Thus your module behaves exactly the same in your test environment as under regular circumstances (except your modifications).

Good news to all caffeine-addicts: rewire works also with Coffee-Script. Note that in this case CoffeeScript needs to be listed in your devDependencies.

SavoryBytes
  • 35,571
  • 4
  • 52
  • 61
5

I am not 100% certain of what you mean by 'invalidate', but you can add the following above the require statements to clear the cache:

Object.keys(require.cache).forEach(function(key) { delete require.cache[key] })

Taken from @Dancrumb's comment here

Lee
  • 29,398
  • 28
  • 117
  • 170
4

I'd add to luff's answer one more line and change the parameter name:

function requireCached(_module){
    var l = module.children.length;
    for (var i = 0; i < l; i++)
    {
        if (module.children[i].id === require.resolve(_module))
        {
            module.children.splice(i, 1);
            break;
        }
    }
    delete require.cache[require.resolve(_module)];
    return require(_module)
}
Krzysztof Wende
  • 3,208
  • 25
  • 38
  • So this is to make the function work in submodules? Nice! A shorter way to remove the module from module.children array is by using a filter function: module.children = module.children.filter(function(child){ return child.id !== require.resolve(_module); }); – luff Apr 06 '14 at 15:09
4

Yes, you can invalidate cache.

The cache is stored in an object called require.cache which you can access directly according to filenames (e.g. - /projects/app/home/index.js as opposed to ./home which you would use in a require('./home') statement).

delete require.cache['/projects/app/home/index.js'];

Our team has found the following module useful. To invalidate certain groups of modules.

https://www.npmjs.com/package/node-resource

fedorqui
  • 275,237
  • 103
  • 548
  • 598
Henry Tseng
  • 3,263
  • 1
  • 19
  • 20
4

requireUncached with relative path:

const requireUncached = require => module => {
  delete require.cache[require.resolve(module)];
  return require(module);
};

module.exports = requireUncached;

invoke requireUncached with relative path:

const requireUncached = require('../helpers/require_uncached')(require);
const myModule = requireUncached('./myModule');
YairTawil
  • 3,961
  • 1
  • 22
  • 20
3

I couldn't neatly add code in an answer's comment. But I would use @Ben Barkay's answer then add this to the require.uncache function.

    // see https://github.com/joyent/node/issues/8266
    // use in it in @Ben Barkay's require.uncache function or along with it. whatever
    Object.keys(module.constructor._pathCache).forEach(function(cacheKey) {
        if ( cacheKey.indexOf(moduleName) > -1 ) {
            delete module.constructor._pathCache[ cacheKey ];
        }
    }); 

Say you've required a module, then uninstalled it, then reinstalled the same module but used a different version that has a different main script in its package.json, the next require will fail because that main script does not exists because it's cached in Module._pathCache

Lux
  • 1,540
  • 1
  • 22
  • 28
bentael
  • 1,987
  • 2
  • 21
  • 27
2

If you want a module to simply never be cached (sometimes useful for development, but remember to remove it when done!) you can just put delete require.cache[module.id]; inside the module.

Kyuuhachi
  • 651
  • 6
  • 15
2

here's my version of this answer, which handles not loading a file if it has (for example) syntax errors

function reacquire(module) {
const fullpath  = require.resolve(module);
const backup = require.cache[fullpath];
delete require.cache[fullpath];

 try {
   const newcopy = require(module);
   console.log("reqcquired:",module,typeof newcopy);
   return newcopy;
 } catch (e) {
    console.log("Can't reqcquire",module,":",e.message);
    require.cache[fullpath] = backup;
    return backup;
 }

}
unsynchronized
  • 4,828
  • 2
  • 31
  • 43
1

Following two step procedure is working perfectly for me.

After changing Model file i-e 'mymodule.js' dynamically, you need to Delete precompiled model in mongoose model first then reload it using require-reload

Example:
        // Delete mongoose model
        delete mongoose.connection.models[thisObject.singular('mymodule')]

        // Reload model
        var reload = require('require-reload')(require);
        var entityModel = reload('./mymodule.js');
Community
  • 1
  • 1
Aqib Mumtaz
  • 4,936
  • 1
  • 36
  • 33
1

The documentation says:

Modules are cached in this object when they are required. By deleting a key value from this object, the next require will reload the module. This does not apply to native addons, for which reloading will result in an error.

OrangeDog
  • 36,653
  • 12
  • 122
  • 207
0

If it's for unit tests, another good tool to use is proxyquire. Everytime you proxyquire the module, it will invalidate the module cache and cache a new one. It also allows you to modify the modules required by the file that you are testing.

Comtaler
  • 1,580
  • 1
  • 15
  • 26
0

I made a small module to delete module from the cache after loading. This forces reevaluation of the module next time it is required. See https://github.com/bahmutov/require-and-forget

// random.js
module.exports = Math.random()
const forget = require('require-and-forget')
const r1 = forget('./random')
const r2 = forget('./random')
// r1 and r2 will be different
// "random.js" will not be stored in the require.cache

PS: you can also put "self-destruct" into the module itself. See https://github.com/bahmutov/unload-me

PSS: more tricks with Node require in my https://glebbahmutov.com/blog/hacking-node-require/

gleb bahmutov
  • 1,801
  • 15
  • 10