Have you heard about Envirotechnical? Let's fight climate change one byte at a time :) Learn More →

logo
Published on

The difference between Nodejs module.exports and exports, a simple technical explanation for 2022

Authors
Table of Contents

TL;DR - module.exports vs exports in Nodejs

module.exports and exports can be used interchangably as long as they reference the same object in memory. If you assign a new object reference to any of them, you will not be able to take advantage of the exports shortcut as intended by Nodejs.

module.exports vs exports in Nodejs, what's the big difference?

Yes, yes, you've read it already a bazillion times and you know all about it, but, there's new people in the market and also are you sure you know what you're talking about?

If you want to jump straight to the conclusion, just head over to the tl;dr section with the help of the TOC component.

I'm not even sure I do either but let's get on with it and be all mad together, just like good ol' Wonderland wanted us to be. Where's the hat by the way?

Alice is mad with the madhatter for losing the hat

No problem, Alice, no problem.

When you started programming in Nodejs you thought that everything was amazing and easy, and it can be, if you approach Nodejs with the best patterns and you respect the language and its ecosystem.

But as you might have noticed during your programming journey, be it the journey of a veteran programmer or a young padawan, every programming language has its own quirks and funny things going around.

Nodejs, joined with the fact that the Javascript Core is part of it, definitely has quite a few of them.

A simple yet powerful item in your Nodejs toolbelt is surely the Module system that the language is shipped with.

For the younger generations or aspiring Noders this might be a little bit off but Nodejs is dependent upon a module system called CommonJS.

The community is striving ever forward in adopting the newer and cleaner approach of ESModules, which is probably how you are used to make use of Javascript, especially if you come from a Front End background (think React), but until a few major versions ago, the strongest Module system was surely CommonJS.

CommonJS is based upon the fact that you require the modules you want to use and those modules are engineered in a way that each file is itself a module and it can export something to those that require it.

// File index.js
const utils = require('./utils')

utils.utilityFn()
// File utils.js
module.exports.utilityFn = () => doSomething

But, as it is the heart of this article, you might also have seen something like this, which is practically the same.

// File index.js
const utils = require('./utils')

utils.utilityFn()
// File utils.js
exports.utilityFn = () => doSomething

If you were to ask about the identity of those objects, you'd find out that

// File utils.js

exports.utilityFn = () => doSomething
module.exports.secondaryFn = () => secondary

const isSameIdentity = module.exports === exports
// true

So, what we are asking above is "is module.exports the same as exports" and the answer is yes, they are the same object, or better, they refer to the same object in memory (read here for more information ).

So, we can use them interchangably? Usually yes, exports is a sweet shortcut that helps us write more concise and shorter amounts of code but it's not a magic wand.

As we stated before, those objects are actually the same object in the memory of our program but if we assign a new one (and everything in Javascript is pretty much an Object) to either of the two, the reference is lost and they will not point "in the same direction" anymore.

console.log(module.exports) // prints empty object {}

module.exports = {} // module.exports starts as an empty object anyway, right?

exports.hello = 'world'
module.exports.ciao = 'mondo'

const isSameIdentity = module.exports === exports // are they the same?!
console.log(isSameIdentity) // well, they are not the same anymore

In fact, by being careless about the module.exports usage, we lose the power to make use of the shorthand exports and whatever we added to exports will actually never be, well, exported.

module.exports = {}

exports.hello = 'world'
module.exports.ciao = 'mondo'

console.log(module)
// Module {
//   id: '.',
//   path: '/App/nodejs',
//   exports: { ciao: 'mondo' },
//   parent: null,
//   filename: '/App/nodejs/index.js',
//   loaded: false,
//   children: [],
//   paths: [
//     '/App/nodejs/node_modules',
//     '/App/node_modules',
//     '/node_modules'
//   ]
// }

So, we learnt that module.exports and exports are the same as long as we treat the referenced object in the proper manner.

To avoid misusage, just remember to assign new references directly to the export object, like so:

exports.hello = 'world'
exports.hallo = 'welt'
exports.hola = 'mon'
module.exports.ciao = 'mondo'
module.exports.pozdrav = 'svijete'
module.exports.ola = 'mundo'

console.log(module)
// Module {
//   id: '.',
//   path: '/App/nodejs',
//     exports: {
//     hello: 'world',
//     hallo: 'welt',
//     hola: 'mon',
//     ciao: 'mondo',
//     pozdrav: 'svijete',
//     ola: 'mundo'
//   },
//   parent: null,
//   filename: '/App/nodejs/index.js',
//   loaded: false,
//   children: [],
//   paths: [
//     '/App/nodejs/node_modules',
//     '/App/node_modules',
//     '/node_modules'
//   ]
// }

The goodbye

I hope you found this article useful and to your liking and if you have any requests, drop a message on one of my social media accounts or open an issue/start a discussion on github, on this repository!

As always you can find me on Twitter, listen to my Podcast on Spotify and add me on LinkedIn to talk professionally (yeah, right)