I am Hack Sparrow
Captain of the Internets.

Node.js Module – exports vs module.exports

What is the difference between exports and module.exports in Node.js?

You must be familiar with the exports object in Node.js modules, using which you create functions in your modules like this (assume in a file named rocker.js):

exports.name = function() {
console.log('My name is Lemmy Kilmister');
};

which you call from another file thus:

var rocker = require('./rocker.js');
rocker.name(); // 'My name is Lemmy Kilmister'

But what the heck is module.exports? Is it even legal?

Here is an eye-opener - module.exports is the real deal. exports is just module.exports's little helper. Your module returns module.exports to the caller ultimately, not exports. All exports does is collect properties and attach them to module.exports IF module.exports doesn't have something on it already. If there's something attached to module.exports already, everything on exports is ignored.

Put the following in rocker.js:

module.exports = 'ROCK IT!';
exports.name = function() {
console.log('My name is Lemmy Kilmister');
};

And this in another file, and run it:

var rocker = require('./rocker.js');
rocker.name(); // TypeError: Object ROCK IT! has no method 'name'

The rocker module completely ignored exports.name, and returned a string 'ROCK IT!'. From that you probably realize that your modules don't always have to be 'module instances'. Your modules can be any legal JavaScript object - boolean, number, date, JSON, string, function, array, and so on. Your module is whatever you set module.exports to. If you don't set module.exports to anything explicitly, the properties of exports and attached to it and returned.

In this case, your module is a class:

module.exports = function(name, age) {
this.name = name;
this.age = age;
this.about = function() {
console.log(this.name +' is '+ this.age +' years old');
};
};

and you'd use it this way:

var Rocker = require('./rocker.js');
var r = new Rocker('Ozzy', 62);
r.about(); // Ozzy is 62 years old

In this case, your module is an array:

module.exports = ['Lemmy Kilmister', 'Ozzy Osbourne', 'Ronnie James Dio', 'Steven Tyler', 'Mick Jagger'];

and you may use it this way:

var rocker = require('./rocker.js');
console.log('Rockin in heaven: ' + rocker[2]); //Rockin in heaven: Ronnie James Dio

So you get the point now - if you want your module to be of a specific object type, use module.exports; if you want your module to be a typical module instance, use exports.

The result of attaching properties to module.exports is akin to attaching properties to exports. For example this:

module.exports.name = function() {
console.log('My name is Lemmy Kilmister');
};

does the same thing as:

exports.name = function() {
console.log('My name is Lemmy Kilmister');
};

But note that, they are not the same thing. As I said earlier module.exports is the real deal, exports is just its little helper. Having said that, exports is the recommended object unless you are planning to change the object type of your module from the traditional 'module instance' to something else.

I hope this post helped you understand the difference between exports and module.exports, and learn a bit more about how modules work in Node.js. Any questions, ping me in the comments.

UPDATE: 7th Feb, 2014

As long are you don't overwrite the module.exports object with an assignment operation, anything attached to module.exports and exports will be available in the 'required' module.

If this is the content of your module:

module.exports.age = 68;
exports.name = 'Lemmy Kilmister';

The following code would work fine:

var rocker = require('./rocker.js');
console.log('%s is %s', rocker.name, rocker.age); // Lemmy Kilmister is 68

BUT

if you overwrite module.exports with anything in your module, it will fail:

module.exports = 'LOL';
module.exports.age = 68;
exports.name = 'Lemmy Kilmister';

or

module.exports.age = 68;
exports.name = 'Lemmy Kilmister';
module.exports = 'WTF';

the order doesn't matter, rocker.age and rocker.name will now be undefined.

Also, note: just because module.exports.age and exports.name are exported, does not mean you should use a combination of both. My recommendation is to stick to exports.*, and be aware of module.exports.*.

24 Responses to “Node.js Module – exports vs module.exports”

  1. kyxbl says:

    i’m afraid the following sentence is wrong:

    “If there’s something attached to module.exports already, everything on exports is ignored.”

    consider this code:

    // b.js
    module.exports.name = “Jim”;
    exports.age = 29;

    // a.js
    var b= require(“./b”);
    console.log(b.name);
    console.log(b.age);

    it works fine

  2. Adam Ahmed says:

    It might help clarify things to show how they are initialized. Essentially before your code runs, there is code that runs like this:

    “`
    var module = {…}; // stuff

    var exports = module.exports = {};
    “`

    So both variables initially point to the same empty Object, but of course can be reassigned to any other value instead. So if you reassign the `exports` variable, it doesn’t affect `module.exports`. Similarly, if you reassign `module.exports`, it no longer affects `exports`. They will be pointing at different values.

    What makes `module.exports` the “real deal” is that when someone `require()`s your module, `require` essential does this:

    “`
    function require(moduleName) {
    var module = getModule(moduleName);
    return module.exports;
    }
    “`

    It might also help to say that `module` is the real deal more than `module.exports` is. Take this code for example:

    “`

    var truth = module;
    var notExports = module.exports;

    truth.exports = { genre: ‘Rock’ };
    notExports.genre = ‘Blues’;
    “`

    ‘Rock’ will be exported. Since `truth` is pointing to `module`, it can make lasting changes to the exports that `notExports` can’t.

  3. Captain says:

    @kyxbl, this post is 6 minor versions and 2 years old, things have changed since. I will be updating it to reflect the changes.

  4. Richard Ayotte says:

    Thanks, looking forward to the update.

Make a Comment