Language: EN


Differences between CommonJS and ESM modules in Node.js

We have seen that Node.js is compatible with files with the extensions .js and .mjs. If it seems a bit confusing to you, hold on, I’ll explain it to you right now.

CommonJS and ECMAScript Modules (ESM) are two module systems used in JavaScript to organize and reuse code in different files.

When Node.js appeared (2009), JavaScript did not have a native module system. Node.js decided to create its own, CommonJS. A decision that we still carry with us today.

Later, JavaScript creates its “official” file system, ECMAScript Modules (ESM) (2015). They were a bit late to the party. But the official syntax had many improvements over the previous ones.

You might say, “well… everything is perfect, we leave behind CommonJS and use ESM!“. By that time, there was so much code that it has taken years to replace them.

In fact, Node.js took until its version 12 (2019) to be compatible with ESM. That’s 10 years of CommonJS. So there are still many tools and libraries that have not been ported.

That’s why there are two extensions:

  • .js works with CommonJS modules 🤔
  • .mjs works with ECMAScript Modules (ESM) 👍

Whenever possible, use ECMAScript Modules (ESM). They are the standard solution, and should replace CommonJS.

Using modules in JavaScript

Let’s see how to use CommonJS and ECMAScript Modules. As mentioned, unless a library is not compatible, or for some other important reason, prefer the latter.

But let’s see the syntax of both, because you will encounter half of the internet documentation, libraries, or projects that you have to deal with, in each system.

CommonJS Legacy

CommonJS is a module system that was developed for use in server environments, such as Node.js. It uses the keywords require and module.exports to import and export modules.

Here is an example of its use.

// Import a module
const otherModule = require('./otherModule');

// Export a module
module.exports = {
  foo: 'bar'

Node.js has used CommonJS as its main module system for a long time.

ECMAScript Modules (ESM) Standard

ECMAScript modules are the standard JavaScript module system defined in the ECMAScript standard (the underlying standard of JavaScript). It uses the keywords import and export to import and export modules, respectively.

Example of its use:

// Import a module
import otherModule from './otherModule';

// Export a module
export const foo = 'bar';

ECMAScript modules are designed to work both in modern web browsers and server environments (such as Node.js), which means they are more portable.

In addition, ECMAScript modules are loaded asynchronously, which can be more efficient in certain scenarios.

JS and MJS Extensions

Before the adoption of ECMAScript modules in Node.js, JavaScript files were written with the extension .js and used CommonJS for importing and exporting code.

Starting from Node.js v12, support for ECMAScript modules was introduced, allowing the use of the same import/export syntax used in modern web browsers.

Since the “good” extension was already taken, they had to call it .mjs. To create a .mjs file, simply name it with that extension, for example: file.mjs. Nothing else is needed.

Both module systems can coexist in the same project. In general, it’s not a good idea. If you can avoid it, that’s better. Although if you can’t, because you would have to rewrite 300 libraries… brace yourself.

Finally, to convert a .js file to .mjs, you simply have to change the extension, and change the require to imports, and the module.exports to exports. But all the libraries and files you use must also be compatible with ECMAScript.