The CommonJS Module System in Node.js
12 min read·Jan 1, 2025
In Node.js, a module is a file that encapsulates related functionality, such as variables, functions, or classes, that can be easily shared and reused into other parts of a project.
Modules help organize code into manageable and maintainable units, promoting code reusability and separation of concerns.
In practice, a module is a .js, .cjs, or .mjs file whose content is private by default, which means that the variables, functions, and classes it contains are inaccessible by the others files composing the application unless they are explicitly exported.
The types of Node.js modules
In Node.js, modules can be of three types: built-in, local, and third-party.
Built-in modules
Built-in modules, also called core modules, are a set of modules that come prepackaged with every Node.js distribution.
They provide essential functionality for interacting with the filesystem, handling networking, performing cryptography, and more.
Local modules
Local modules are created by developers to organize their code into reusable and maintainable units.
These modules are specific to a particular project and are usually stored in separate files within the project directory.
Developers can create their own modules by defining functions, classes, or variables in one file and then exporting them for use in other files.
Third-party modules
Third-party modules are modules created by external developers or the open-source community.
These modules are not part of the Node.js core, and developers can use package managers like npm to install and manage them.
Third-party modules provide a wide range of additional functionalities, such as HTTP frameworks, database connectors, utility libraries, and more.
Importing CommonJS modules
The CommonJS module system is the original way to package JavaScript code for Node.js.
To import a CommonJS module into another file, you can use the global require function:
const module = require(source);
Where:
-
moduleis an arbitrary variable name given to the imported module that stores the exported variables, functions, and classes. -
sourceis either the name of the built-in or third-party module, or the relative or absolute path to the local module.
Importing a core module
As mentioned, Node.js comes prepackaged with an extensive list of core modules, such as buffer for handling binary data, fs for manipulating the filesystem, http for creating HTTP servers, and so on.
To import a core module, you can specify its name prefixed with "node:" as an argument of the require function:
const module = require('node:module');
Upon execution, Node.js will automatically try to resolve this module by loading its implementation from the core modules directory, or output an error if not found.
Example
In this example, Node.js will automatically resolve the core fs module and assign its exported functionalities to the fs variable:
const fs = require('node:fs');
Importing a local module
To import a local module, you can specify its relative or absolute path as an argument of the require function:
const module = require('path/to/local_module');
Upon execution, Node.js will try to import this module based on the provided path, or output an error if not found.
Example
In this example, Node.js will try to import the local calc.js module located in the current directory and assign its exported functionalities to the calc variable:
const calc = require('./calc.js');
Importing a third-party module
Similar to importing a core module, to import a third-party module installed through a package manager like npm or Yarn, you can pass the name of the module as an argument of the require function:
const module = require('third_party_module');
Upon execution, Node.js will automatically try to resolve this module by loading its implementation from the local node_modules directory, the cache directory, or output an error if not found.
You will learn more about this later in the branch on the Node Package Manager.
Example
In this example, Node.js will try to import the third-party express module and assign its exported functionalities to the express variable:
const express = require('express');
Creating a CommonJS module
To create a CommonJS module, you need to first create a new .js or .cjs file:
$ touch module.js
Exporting a single functionality
To make a single variable, function, or class available to other parts of your application, you need to override the value of the global module.exports variable using the assignment operator =:
module.exports = expression;
Example
Let's consider this module, that exports a single function named add:
// File: calc.js
const add = (a, b) => a + b;
module.exports = add;
Let's consider this script, that imports and uses the function exported by the calc.js module:
// File: script.js
const add = require('./calc.js');
console.log(add(3, 1));
When executed, it will:
-
Import the function exported by the
calc.jsmodule into a variable namedadd. -
Output the execution result of the
addfunction.
Which will produce the following result:
$ node script.js
4
Exporting multiple functionalities
By default, the global module.exports variable contains an empty object literal {}.
To make multiple variables, functions, or classes available to other parts of your application, you can either extend this object with new properties:
module.exports.property = expression;
Or you can completely override it with another object literal:
module.exports = {
property: expression
...
};
Example
Let's consider this module, that exports two functions named add and subtract:
// File: calc.js
const add = (a, b) => a + b;
const subtract = (a, b) => a - b;
module.exports = {
add,
subtract
};
Let's consider this script, that imports and uses the functions exported by the calc.js module:
// File: script.js
const calc = require('./calc.js');
console.log(calc.add(3, 1));
console.log(calc.subtract(3, 1));
When executed, it will:
-
Import the object exported by the
calc.jsmodule into a variable namedcalc. -
Output the execution result of the
calc.add()method. -
Output the execution result of the
calc.subtract()method.
Which will produce the following result:
$ node script.js
4
2
Note: In the context of modules, the destructuring assignment syntax is often used to only import the components that are necessary at hand, thus preventing the pollution of the global scope.
Since the
module.exportsvariable of the previous example holds an object, the import statement could have been rewritten using this syntax:const { add, subtract } = require('./calc.js');
Summary
Here's a summary of what you've learned in this lesson:
-
A module is a file that encapsulates related functionality that can be shared and reused into other parts of a project.
-
A built-in module is a core module that comes prepackaged with every Node.js distribution.
-
A local module is a local module created by developers in a particular project.
-
A third-party module is an external module created by other developers available through package managers.
-
The global
require()function is used to import a module in CommonJS. -
The global
module.exportsvariable is used to export one or more functionalities from a module in CommonJS.
Enjoying the courses?
I've made these courses completely free so anyone can learn from them. If they've helped you and you'd like to actively support the work behind BackendBrewery, you can leave a tip:
Support BackendBrewery