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:

  • module is an arbitrary variable name given to the imported module that stores the exported variables, functions, and classes.

  • source is 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:

  1. Import the function exported by the calc.js module into a variable named add.

  2. Output the execution result of the add function.

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:

  1. Import the object exported by the calc.js module into a variable named calc.

  2. Output the execution result of the calc.add() method.

  3. 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.exports variable 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.exports variable 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
The CommonJS Module System in Node.js | Backend Brewery