JavaScript
Article
By Cho S. Kim

Understanding module.exports and exports in Node.js

By Cho S. Kim

As developers, we often face situations where we need to use unfamiliar code. A question will arise during these moments. How much time should I invest in understanding the code that I’m about to use? A typical answer is learn enough to start coding; then explore that topic further when time permits. Well, the time has come to gain a better understanding of module.exports and exports in Node.js. Here’s what I have learned.

Note: This post covers using modules in Node. If you want to learn how you can use modules inside of the browser, read: Understanding JavaScript Modules: Bundling & Transpiling

What is a Module

A module encapsulates related code into a single unit of code. When creating a module, this can be interpreted as moving all related functions into a file. Let’s illustrate this point with an example involving an application built with Node.js. Imagine that we created a file called greetings.js and it contains the following two functions:

// greetings.js
sayHelloInEnglish = function() {
  return "Hello";
};

sayHelloInSpanish = function() {
  return "Hola";
};

Exporting a Module

The utility of greetings.js increases when its encapsulated code can be utilized in other files. So let’s refactor greetings.js to achieve this goal. To comprehend what is actually happening, we can follow a three-step process:

1) Imagine that this line of code exists as the first line of code in greetings.js:

// greetings.js
var exports = module.exports = {};

2) Assign any expression in greetings.js that we want to become available in other files to the exports object:

// greetings.js
// var exports = module.exports = {};
        
exports.sayHelloInEnglish = function() {
  return "HELLO";
};
   
exports.sayHelloInSpanish = function() {
  return "Hola";
};

In the code above, we could have replaced exports with module.exports and achieved the same result. If this seems confusing, remember that exports and module.exports reference the same object.

3) This is the current value of module.exports:

module.exports = {
  sayHelloInEnglish: function() {
    return "HELLO";
  },
       
  sayHelloInSpanish: function() {
    return "Hola";
  }
};

Importing a Module

Let’s import the publicly available methods of greetings.js to a new file called main.js. This process can be described in three steps:

1) The keyword require is used in Node.js to import modules. Imagine that this is how require is defined:

var require = function(path) {

  // ...

  return module.exports;
};

2) Let’s require greetings.js in main.js:

// main.js
var greetings = require("./greetings.js");

The above code is equivalent to this:

// main.js
var greetings = {
  sayHelloInEnglish: function() {
    return "HELLO";
  },
       
  sayHelloInSpanish: function() {
    return "Hola";
  }
};

3) We can now access the publicly available methods of greetings.js as a property of our greetings variable in main.js.

// main.js
var greetings = require("./greetings.js");

// "Hello"
greetings.sayHelloInEnglish();
        
// "Hola"  
greetings.sayHelloInSpanish();

Important Points

The keyword require returns an object, which references the value of module.exports for a given file. If a developer unintentionally or intentionally re-assigns module.exports to a different object or different data structure, then any properties added to the original module.exports object will be unaccessible.

An example will help elaborate this point:

// greetings.js
// var exports = module.exports = {};

exports.sayHelloInEnglish = function() {
  return "HELLO";
};

exports.sayHelloInSpanish = function() {
  return "Hola";
};

/* 
 * this line of code re-assigns  
 * module.exports
 */
module.exports = "Bonjour";

Now let’s require greetings.js in main.js:

// main.js
var greetings = require("./greetings.js");

At this moment, nothing is different than before. We assign the variable greetings to any code that is publicly available in greetings.js.

The consequence of re-assigning module.exports to a data structure other than its default value is revealed when we attempt to invoke sayHelloInEnglish and sayHelloInSpanish:

// main.js
// var greetings = require("./greetings.js");
    
/*
 * TypeError: object Bonjour has no 
 * method 'sayHelloInEnglish'
 */
greetings.sayHelloInEnglish();
        
/* 
 * TypeError: object Bonjour has no 
 * method 'sayHelloInSpanish'
 */
greetings.sayHelloInSpanish();

To understand why these errors are occuring, let’s log the value of greetings to a console:

// "Bonjour"
console.log(greetings);

At this point, we are trying to access the methods sayHelloInEnglish and sayHelloInSpanish on the string “Bonjour.” module.exports, in other words, is no longer referencing the default object that contain those methods.

Conclusion

Importing and exporting modules is a ubiqutous task in Node.js. I hope that the difference between exports and module.exports is clearer. Moreover, if you ever encounter an error in accessing publicly available methods in the future, then I hope that you have a better understanding of why those errors may occur.

There are many ways to start a local Node server. Watch as this screencast explores some of the common node server techniques and how to instantiate them.

More:
  • jokeyrhyme

    I’ve found it less confusing to just avoid the `exports` variable altogether.

    • Cho S. Kim

      That makes a lot of sense.

    • Bushwazi

      Can you explain this more? I tried changing `exports.sayHelloInSpanish = function(){return “Hola”;}` to `sayHelloInSpanish = function(){return “Hola”;}` and I got an error. And `console.log(greetings);` just returned and empty object {}. Do you have to structure greetings.js different to make it work this way?

      • jokeyrhyme

        This article looks at exports and module.exports.

        Given the choice, I avoid exports, and only use module.exports.

      • Cho S. Kim

        Bushwazi,
        I believe that jokeyrhyme’s initial comment could have been misinterpreted for avoiding the use of both exports and module.exports. He clarified what he meant in his reply to your question (using module.exports instead of exports), but I’ll try to answer your question, too.

        Question 2 of 2: console.log(greetings);
        Imagine this is the file we are talking about and the comments represent code that’s implied:

        // var module.exports = {};

        sayHelloInSpanish = function() {
        return “Hola”;
        };

        // module.exports = {};

        When you require this file in a different file, you’re returning module.exports. In this case, you never added a method called sayHelloInSpanish to module.exports. So this explains why an empty object is being returned in the console.

        Question 1 of 2: you received an error
        This may be in reference to a syntactical error. I can confirm this if you provide more information, such as the code in the file you are using. Or you can tell me the type of error; however, seeing the file is probably the easiest approach.

        I hope this helps.

        • Bushwazi

          Sorry, it’s obvious now that I look again. jokeyrhyme’s just saying he prefers this pattern (is this a constructor/ object initializer?):

          module.exports = {

          methodName: function(){}

          }

          and you were showing a different pattern (and this is “Dot syntax”?):

          exports.mathodName = function(){};

          to accomplish the same thing.

          Let me know if I still don’t get it…

          • Cho S. Kim

            Yes, he was using an object literal to add methods and I was using dot notation to add methods. Both syntax works, but I choose the later because adding a lot of methods to an object literal delays the end of the object literal (closing curly brace) for many lines of code.

            I hope this helps.

          • Bushwazi

            Yeah man, this was great. Thank You!

          • This is the explanation I was waiting for. The reason to choose one or the other way to export the functions. I was using the same than you (exports.name = function) but just for a reason of that I have some functions that I don’t want to export (are helpers) and other than yes. Now I know that it has a little performance reason too.

  • Dave McFarland

    I’m sorry I don’t get it. What IS the difference between exports and module.exports? It sounds like they are the same thing: “In the code above, we could have replaced exports with module.exports and achieved the same result. If this seems confusing, remember that exports and module.exports reference the same object.”

  • ConnieRWright

    Start working at home with>>CLICK NEXT TAB FOR MORE INFO AND HELP

  • Cho S. Kim

    Dave,

    Thanks for leaving a comment. Both module.exports and exports initially reference the same object:

    var exports = module.exports = {};

    But this could change if a developer re-assigns module.exports or exports to a different object (or entirely different data type). This usually occurs when developers use exports and module.exports interchangeably and incorrectly to make assignments in the same file.

    Here’s the difference between exports and module.exports: When a module is being required in a file, what’s being returned from the require function is the value of module.exports. So this is worth repeating, the difference is that the require function returns only the value of module.exports, which initially references an object.

  • rosy lily

    I get paid over $87 per hour working from home with 3 kids at home. I never thought I’d be able to do it but my best friend earns over 10k a month doing this and she convinced me to try. The potential with this is endless.

    Here ­­­­­­­­­is ­­­­­­­­­I ­­­­­started>>>>>>>>>➜➜➜➜➜➜➜

    ➜➜➜➜ W­W­W­.­N­E­T­P­A­Y­1­0­.ℭ­ℴ­m

    —————————————————–

    GO TO THE SITE –>>>CLICK NEXT TAB FOR MORE INFO AND HELP

  • Quynh Le

    Thank you very much. It is clear now for me.

  • nor

    The principal difference is what module.exports replace the content of the exports only if exports previously has an value and this is only valid if you have the declaration exports first and then you write module.export. In summary use one of it not both.

  • Alex

    Thank so much for this very clear presentation. Very helpful to me.

  • Mustafa Gamal

    Thanks for the simplicity :)

  • Vengatesh TR

    wow. beautiful & detailed explanation. Thanks :)

  • You’re welcome :).

  • I’m happy that it was useful.

  • Jahanzaib Aslam

    Simple and to the point. Thanks

  • Darnell Filliams

    Thank you very much. This was very clear and well-written.

  • ConfusedCoder

    Thank you! Simple and clear, great tutorial!

  • joe

    var module.exports = { } is a syntax error. You can’t use member variables in var declaration.

    • Hey, Joe. I believe that you’ve misread the syntax:
      var exports = module.exports = {};
      Considering the syntax above, the pointers move from right to left. So it’s more like this:
      module.exports = {};
      then
      var exports = modules.exports

  • Luke Swart

    Thanks for the post! We need more elegant explanations for ubiquitous topics such as module exports.

  • Sergey Gulidov

    Thanks, it was useful for me)

  • Andrew Hung

    Great explanation, Cho. Thanks for writing this. Definitely cleared things up for me.

  • Thanks, it was useful tutorial

  • Clint Goodman

    Hey this was excellent. Thank you very much. I loved the way that you helped me visualize what was going on. I want to read more of your stuff.

    • @clint_goodman:disqus,
      Thanks for the positive feedback. I’ll let you know when I publish more content.

  • David Christiandy

    It is actually the same thing. Here’s a simple way to put it: imagine that `module` is just plain Javascript object:

    var module = {}
    var exports = module.exports = {}

    module.exports.hello = “Bonjour”
    console.log(module.exports) // Object {hello: “Hello”}
    console.log(exports) // Object {hello: “Hello”}

    exports = null;
    console.log(module.exports) // Object {hello: “Hello”}
    console.log(exports) // null

    • Chi

      Hmmm… so according to your example, exports initially points to module.exports by default. You invalidate the pointer by pointing “exports” to null or any other object for that matter. I finally get how this process works. Thanks!

    • var module = {}
      var exports = module.exports = {}

      So basically the way you set it up, on that second line, exports plays “follow the leader” to module.exports until you explicitly set exports equal to something else by doing something like:
      exports = null

      My question is, why create an arbitrary “exports” variable in the first place? I’m guessing it’s just for convenience, and not wanting to write out “module.exports” all the time.

  • Ranks high in google search.
    It is very helpful for understanding commonJS.
    Thanks for sharing this!

  • Dan Chan

    I followed your example. But, it did not work. I got this error:

    “Uncaught Error: Module name “/greetings.js” has not been loaded yet for context: _. Use require([])

    http://requirejs.org/docs/errors.html#notloaded

    Any idea? What did I do wrong?

    Thanks.

    • @dc7669:disqus,
      Sorry for not responding sooner. @nazmulhoqueshafin:disqus, noticed the error. You’re loading your own module and you didn’t specify the path correctly to it.

  • Ademola Adedeji

    Thank you

  • Aurelius

    Thanks this was helpful

  • lacyrhoades

    Thank you!

  • Frank Wang

    very helpful!

  • Nazmul Hoque Shafin

    just put a period (.) before the “/.greetings.js” . I mean you should write require(“./greetings.js”); instead of equire(“/greetings.js”);

  • D. Attila

    Easy to follow and crystal clear, many thanks!

  • Slight error in the document. It appears the expression for your Author isn’t evaluating because the closing brace is a bracket (or vice versa):

    {author_more]

    Other than that great points. I personally prefer to section out my module with many exports statements then returning one large object, but both have their purpose. If I create a large class than module.exports comes in handy, but if I am creating a handful of utility functions, then exports(dot) is my best friend.

    • @tylermaynard:disqus,
      Thanks for bringing the error about the closing to my attention. I’ll forward this info to the editor.

      In regards to other comments, they seem very logical.

  • GJ

    Thank you much. Very helpful.

  • Jordan Neufeld

    Cho,
    Thank you for this post!

  • Joseph Diku

    Thank You for the write up, it’s clearer to me now

  • Mahmod Issa

    Thanks a lot, clarified some points that I was in doubt!

  • Pride007

    Really good explanation, finally it’s all clear. thanks Kim

  • Paulo Matos

    It was really useful. Thank you!

  • Hello Cho, thank you very much for this article, it is very helpful! :)

  • Goon

    Simple. Clear. Awesome.

  • Good tips Cho! Exactly what I was looking for. Thanks.

  • Vitez Koja

    Ty you Sir :)

  • Francis Kwan

    thank you . this is very clear explanation. :)

  • Ronak Amlani

    Thank you thank you so much..

  • UATP

    Isn’t the reason that module.exports and exports refer to the same object simply because of the line:

    var exports = module.exports = {};
    What is odd is that it exists in 1.) but it’s commented out in 2.), so either it’s commented because it’s meant to be a comment about what is happening behind the scenes or because it’s a typo in the example.

    Still a little confused.

    • @uatp:disqus : Sorry for the delay. It’s the former–a comment about what’s happening.

  • Welquer Kestering Esser

    Thank you, it helped me a lot!

  • Hi, thank you for the tutorial.
    Currently, with node 5.5.0 I found:

    exports = ‘Hello’; // {}

    exports.hello = ‘Hello’; // {hello: ‘Hello’}

    module.exports = ‘Hello’; // {hello: ‘Hello’}

    module.exports.hello = ‘Hello’; // {hello: ‘Hello’}

    so, it seems exports and module.exports are not the same

    • Ming Hann

      always use module.exports. nuff said.

  • Interesting article thanks!

  • Brendan Moran

    Great explanation! So clear, I feel like I’ve really got a handle on it now. Thank you.

  • milind

    Thanks Cho S. Kim,Realy very useful tutorial.

  • Nick Restrepo

    “Here’s his blog” – BAM Chinese words everywhere. Really cool font though.

    • @nick_restrepo:disqus, ehk. I let my domain name expire, and someone decided to take it…even though they have no connection with my name.

      I recently bought a new domain name, and I’ll give SitePoint the updated link, soon.

  • Nilson Jacques

    Hey Thanasis, I may be misunderstanding your critcism, but the Node.js docs seem to agree with what is being said in the article, and Cho specifically warns against assigning a new value to module.exports in the last section. If you have more specific criticism of the information presented, I’d be happy to take a look.

    • The Master

      @nilsonjacques:disqus please ignore @thanpolas:disqus , he is a well-known troll in Greek forums, he is always sarcastic and criticizes other article writers without any profound reason, he just like to be negative.

      Cho’s article is really very helpful and well written for beginners.

      • lol, said the random anonymous user.

        • The Master

          thanks lad, keep being sarcastic for no reason :)

    • Hey Nilson, you are overwriting `exports` on your very first step in your very first example. That is a major anti-pattern and deadly confusing to new developers trying to grasp the concepts of exporting in node.js. The fact that the documentation explains what will happen if you do indeed do this major anti-pattern, is irrelevant to the point that you are overwriting a global variable provided to you by node, with the same value it already has defined.

      • Nilson Jacques

        Are you referring to the first code example under the ‘Exporting a Module’ heading? E.g. the line var exports = module.exports = {};? If so, this is an ‘imaginary’ line of code to show the reader the relationship between the two that Node provides. If you look at the line above the example, it says “imagine that this line of code exists as the first line of code in greetings.js”. It’s most definitely not instructing anyone to add that to their code.. it’s just psuedo-code for teaching purposes.

  • Yishagerew lulie

    Interesting article, used require and exports without really knowing them :)

  • Santosh Kumar

    Saved my life. I was trying to hide my api keys. Made a specific file with keys. Removed it from git repository with .gitignore. Works as charm!

  • David Kurutz

    agreed, thank you.

  • Hadeel Alfoqahaa

    helpful blog (Y)

  • Franck Freiburger

    Maybe it might interest some of you, I have created a node.js module that allows you to invalidate a module and then make it automatically reloaded on further access without need to call require() again.
    see: https://github.com/FranckFreiburger/module-invalidate

  • Nguyen

    Thank you so much, good job :)

  • Honestly this isn’t a spectacular explanation. Read it 3 times and still not clear

  • Suhail Mumtaz Awan

    Great, this article i must read before, simple and effective

  • TheBigZocker

    So, both ‘module.exports’ and ‘exports’ exist from the start and initially point at the same object. That’s all.
    You can use ‘exports’ as a shorthand to access ‘module.exports’ per dot notation but reassigning it is a bad idea because
    in the end only ‘module.exports’ is exported and not whatever the variable ‘exports’ points to at that time.

  • The Master

    λες ε; είσαι ο κλασσικός σπαζοκλαμπάνιας της παρέας που σου φταίνει όλα και έχεις άποψη για όλα, ε;

  • Ahmed Saad

    Thanks, very helpful

  • Andreas Marshall

    Great info! Easy to read and easy to understand.

  • Shashank Dahake

    Great

Recommended
Sponsors
Get the latest in JavaScript, once a week, for free.