When you write Node.js applications, you could actually put all your code into one huge index.js file, no matter how large or complex your application is. The Node.js interpreter doesn’t care. But in terms of code organization, you would end up with a hard to understand and hard to debug mess quite quickly. So as a human being, you should care about how to structure your code. This is where modules come in.

You can think of Node.js modules as JavaScript libraries - a certain part of your overall codebase (for example, a collection of functions) which you want to keep together, but which you also want to keep separated from the rest of your codebase to keep things cleanly separated.

Just like we keep our socks in one drawer and our shirts in another drawer in our wardrobe - even if we combine both to create an outfit for the day - we can keep different parts of our codebase in different modules and then combine them into a coherent application.

Built-in Modules

Even if we don’t create any Node.js modules ourselves, we already have modules at our disposal because the Node.js environment provides built-in modules for us. We already encountered one of these modules in this blog when we looked at how to use the built-in WHATWG URL parser.

Within our own code file, we needed to use existing code which was declared elsewhere - in this case, the URL class which is part of the built-in Node.js module url:

var URL = require('url').URL;

The require('url') part is what gives us access to the code of the url module. Where and how this module is defined is completely opaque for us - all we need to know is its name - url - and the attributes it exposes, like URL.

Other built-in modules directly expose the attribute we need (which often are JavaScript objects). The http module is an example:

var http = require('http');

http.createServer(function (req, res) {
    res.writeHead(200, {'Content-Type': 'text/html'});
    res.end('Hello World!');
}).listen(8080);

Here, requiring the http module gives us direct access to an http object, whose methods, like createServer, we can then use.

The Node Beginner Book explains how to write a complete web server with Node.js using the built-in http module.

External Modules

The built-in modules which ship with Node.js allow to solve a lot of coding problems without reinventing the wheel for every new application, but what really boosts Node.js programming productivity is the huge ecosystem of open source modules provided by the Node.js community. These modules can be integrated into our codebase, too, but because they are not built-in and don’t ship directly with each installation of Node.js, it is not enough to require them from our own code. We need to install the codebase containing the external module locally first, which is made very easy thanks to NPM, the Node Package Manager.

See this blog post which describes how to use the async library for an example of how to use external modules.

Also, The Node Craftsman Book has a chapter on the details of working with NPM.

Creating your own modules

Built-in and external modules are provided by others, but nothing stops you from creating your own Node.js modules.

The following example creates a module myRandom which provides a helper function that returns random number between 1 and 10:

File myRandom.js:

function getRandom(min, max) {
      return Math.random() * (max - min) + min;
}

exports.between1and10 = function() {
      return getRandom(1, 10);
};

You would put this code into it’s own file called myRandom.js. Because this file exists and provides attributes to the outer world via exports, another file index.js can use the exported functionality:

File index.js:

var myRandom = require('./myRandom.js');

console.log(myRandom.between1and10());

Again, require comes into play, making the exported attributes of the local myRandom module available - in this case, the between1and10 function.

Note: While the module system allows to expose functionality of a module, it also allows to hide functionality which is not needed outside of the module, simply by not exporting the functionality via exports. Even though the index.js file has required the myRandom.js file, it cannot access its non-exported getRandom function:

var myRandom = require('./myRandom.js');

console.log(myRandom.getRandom(5, 99));

will result in a TypeError: myRandom.getRandom is not a function.

By hiding implementation details in a module and only exposing those parts which are to be used by other parts of your codebase, you can keep your codebase well organized.


Learn more about working with modules and building your own web server application with Node.js with The Node Beginner Book - the first part of this step-by-step Node.js tutorial is available for free!