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

Let's first take a look at what the module object is all about. Create a file named run.js with the following content.

run.js
console.log(module);

Then execute the file using node. You should see an output which looks something like this:

$ node run.js
Module {
  id: '.',
  exports: {},
  parent: null,
  filename: '/Users/yaapa/projects/hacksparrow.com/run.js',
  loaded: false,
  children: [],
  paths:
   [ '/Users/yaapa/projects/hacksparrow.com/node_modules',
     '/Users/yaapa/projects/node_modules',
     '/Users/yaapa/node_modules',
     '/Users/node_modules',
     '/node_modules' ] }

So it looks like module is a contextual reference to the file you just executed.

Did you notice it has an exports property? Which is an empty object. That's where you define the 'importable' objects of your module.

Now edit run.js and run it again:

run.js
exports.a = 'A';
exports.b = 'B';
$ node run.js
Module {
  id: '.',
  exports: { a: 'A', b: 'B' },
  ...

You can see that assigning properties to the exports object has added those properties to modules.exports.

That is because exports is a reference to modules.exports.

You can confirm it with the following code:

run.js
exports.a = 'A';
console.log(exports === module.exports);
console.log(module.exports);
$ node run.js
true
{ a: 'A' }

So, assing properties to the exports object is a neat shortcut if you want to export an object from your module:

Using module.exports:

module.exports = {
  greet: function (name) {
    console.log(`Hi ${name}!`);
  },

  farewell: function() {
    console.log('Bye!');
  }
}

Using exports:

exports.greet = function (name) {
  console.log(`Hi ${name}!`);
}

exports.farewell = function() {
  console.log('Bye!');
}

Defining the properties on exports certainly looks better than defining them on an object assigned to module.exports.

Do you like surprises?

You have no choice - exports is not a reference to modules.exports all the time!

If you assign anything to module.exports, exports is not no longer a reference to it, and exports loses all its power.

run.js
module.exports = {a: 'A'};
exports.b = 'B';
console.log(exports === module.exports);
console.log(module)
$ node run.js
false
Module {
  id: '.',
  exports: { a: 'A' },
  ...

So, now you know, exports is shortcut for referencing module.exports, if your module is to export an object. It is a pretty much usless object if your module exports any other data type or you have assigned anything to module.exports.

References#

  1. Node.js - module object
  2. Node.js - module.exports