Node.js official docs are excellent at explaining the two different types of module systems. CommonJS and ESM.

There is a very good chapter in Node.js Design Patterns, Chapter 2: The Module System (2020) that describes where CommonJS came from. It emerges from the need to provide a module system for JavaScript in browserless environments simply because one did not exist, other than the AMD and UMD initiatives, and to not rely on urls and <script> tags for resources. It was successful so became popular.

We now have ECMAScript Modules thanks to the ES2015 official proposal and it attempts to align the management of modules in both server-side and browser environments.

The main points to help you decide are:

  1. CommonJS uses the require function to load modules and is synchronous. As a result, when you assign a module to module.exports for example, it too must be synchronous. If you have asynchronous stages in your module then you can export an uninitialized module but using require will mean that there is a chance it won't be ready to use in the code that requires it before it's initialized. An example of exporting and importing might look like this:
// titleCase.cjs

function titleCase(str) {
   if (!str){
      return '';
   }
   return str.toLowerCase().split(' ').map(word => {
      if (!word){
         return word;  
      }else{
         return word.charAt(0).toUpperCase() + word.slice(1);
      }
   }).join(' ');
}

module.exports = titleCase;
// app.js

const titleCase = require('./titleCase');
console.log(titleCase('the good, the bad and the ugly'));

// "The Good, The Bad And The Ugly"
  1. ES modules use the import keyword to load modules and the export keyword to export them. They are static, so they need to be described at the top level of every module and support loading modules asynchronously. ES modules facilitate static analysis of the dependency tree, making dead code elimination (tree shaking) more efficient. The same titleCase function above using ESM would look like:
// titleCase.js

export default function titleCase(str) {
   if (!str){
      return '';
   }
   return str.toLowerCase().split(' ').map(word => {
      if (!word){
         return word;  
      }else{
         return word.charAt(0).toUpperCase() + word.slice(1);
      }
   }).join(' ');
}
// app.js

import titleCase from './titleCase.js'; //< File extension required on import
console.log(titleCase('the good, the bad and the ugly'));

// "The Good, The Bad And The Ugly"
  1. ES modules run implicitly in strict mode (can't be disabled). This is a good thing in many opinions as it enforces good coding practices.
  2. In CommonJS you can use the helpful __filename and __dirname. In ES modules you need to do a workaround to get the same functionality like so:
import { fileURLToPath } from 'url'
import { dirname } from 'path'
const __filename = fileURLToPath(import.meta.url)
const __dirname = dirname(__filename)
  1. You can dynamically load modules in CommonJS with require:
let usefulModule;
if (process.env.DEV === true) {
   usefulModule = require('./utils/devmodule')
} else {
   usefulModule = require('./utils/prodmodule')
}
  1. And in ESM by using import as function:
let lib;
if (process.env.DEV === true) {
   lib  = await import('./utils/devmodule.js');
} else {
   lib  = await import('./utils/prodmodule.js');
}
const usefulModule = lib.usefulModule;

One thing I have noticed over the years of programming is that languages and libraries evolve. I have observed a growing shift in Node package docs giving more and more of their examples in ESM format. CommonJS is still the dominant option on npm but it tells me the ecosystem is slowly shifting away from CommonJS and towards ESM. Maybe they will run in tandem but such is the nature of evolution, one becomes dominant over the others. All of the projects I work on use the ESM approach. Good luck deciding.

Answer from jQueeny on Stack Overflow
🌐
LogRocket
blog.logrocket.com β€Ί home β€Ί commonjs vs. es modules in node.js
CommonJS vs. ES modules in Node.js - LogRocket Blog
June 20, 2024 - JavaScript modules have evolved greatly over the years, starting with the IIFE, which prevents global pollution of the global scope and allows code encapsulation, to the Module pattern, which provides a clearer separation between private and public components of a module, solving the growing complexity in JavaScript applications. However, both the IIFEs and Module patterns did not have a standard way of managing dependencies, which necessitated better development solutions. CommonJS was primarily intended for server-side development with Node.js.
🌐
Medium
medium.com β€Ί globant β€Ί exploring-node-js-modules-commonjs-vs-es6-modules-2766e838bea9
Exploring Node.js Modules: CommonJS vs. ES6 Modules | by Jitesh Verma | Globant | Medium
May 8, 2023 - CommonJS modules have been the traditional method for handling dependencies in Node.js, whereas ECMAScript modules are a newer addition and follow the standard format used in modern browsers.
Discussions

Common JS vs ES Modules and why?
CommonJS is old, but Node tries to hold on to backwards compatibility as much as it can, but forward compatibility is a whole 'nother story. The major difference is, import is an asynchronous means of including modules, where as require is synchronous. CommonJS does not support async in the root of a module, import itself does exist in CommonJS, just not in the root level of a module (file). If you create an async function, you can all and await import from inside of it. ESM will handle the root level async imports for you, and provide a whole realm of future features going forward. ESM can consume and use CommonJS modules, but CommonJS cannot consume ESM modules, it's a one way street. A module either has to explicitly output both an ESM and a CommonJS output, and be configured in such a way that it exposes both in a resolvable fashion. In some cases people use a simple wrapper to achieve this, but it does not come without it's pains. This is mostly only an issue if you're building something with the intention of publishing it to npm where it will be consumed by a wider audience. Because whether or not you support both impacts who can consume your API. The reason you get this error: Cannot use import statement outside of a module Is because the backend project where you're using import is currently set to be CommonJS. You should add: { ... type: "module" ... } to your package.json in your backend project. If you'd like to see a TypeScript project configured to support both commonjs and ESM, without relying on any additional dependencies to do so, you can see my csrf-csrf project here, which has a package.json and a tsconfig, and some scripts, configured to output and publish a module to npm which natively supports both. More on reddit.com
🌐 r/node
7
26
December 9, 2022
node.js - Is there any performance difference in ES modules vs Common JS modules in NodeJS servers? - Stack Overflow
Is there any performance advantage or disadvantage of using ES modules over CommonJS modules in a nodejs backend project? I'm asking this because I see a lot of people using CJS still even though n... More on stackoverflow.com
🌐 stackoverflow.com
CommonJS vs ES6 import/export: which is the standard?
ES6 modules and the import and export keywords are the standard. The specification is written by the ECMA TC39 (technical committee in charge of the language standards). However, it's (in relative terms) recent and since JavaScript didn't support modules prior to it, workarounds were developed. These include CommonJS (NodeJS modules) and AMD (RequireJS modules). On Node, CommonJS is going strong and there's a bit of a conflict regarding the "migration" to the standard, so there you likely don't get to choose. However, if you use JavaScript modules on browsers, you probably have a build step that bundles up your modules with something like Webpack or Browserify (at least until module loading is handled across the all relevant browsers). There you should definitely go for the standard ES6 modules and it's considered best practice. More on reddit.com
🌐 r/javascript
1
0
April 19, 2017
CommonJS vs AMD vs RequireJS vs ES6 Modules
Posted by u/[Deleted Account] - 1 vote and 1 comment More on reddit.com
🌐 r/javascript
1
1
September 30, 2018
People also ask

What’s the main difference between CommonJS and ES Modules?
CJS loads modules synchronously with require(), while ESM uses async import/export and supports tree‑shaking.
🌐
syncfusion.com
syncfusion.com β€Ί blogs β€Ί javascript β€Ί commonjs vs es modules in javascript: core differences, practical use cases, and best practices
CommonJS vs ES Modules in JavaScript: Core Differences, Practical ...
Is it worth migrating a CommonJS project to ES Modules?
It depends on your tooling and dependencies. Migration improves long‑term maintainability but requires non‑trivial changes.
🌐
syncfusion.com
syncfusion.com β€Ί blogs β€Ί javascript β€Ί commonjs vs es modules in javascript: core differences, practical use cases, and best practices
CommonJS vs ES Modules in JavaScript: Core Differences, Practical ...
Top answer
1 of 3
48

Node.js official docs are excellent at explaining the two different types of module systems. CommonJS and ESM.

There is a very good chapter in Node.js Design Patterns, Chapter 2: The Module System (2020) that describes where CommonJS came from. It emerges from the need to provide a module system for JavaScript in browserless environments simply because one did not exist, other than the AMD and UMD initiatives, and to not rely on urls and <script> tags for resources. It was successful so became popular.

We now have ECMAScript Modules thanks to the ES2015 official proposal and it attempts to align the management of modules in both server-side and browser environments.

The main points to help you decide are:

  1. CommonJS uses the require function to load modules and is synchronous. As a result, when you assign a module to module.exports for example, it too must be synchronous. If you have asynchronous stages in your module then you can export an uninitialized module but using require will mean that there is a chance it won't be ready to use in the code that requires it before it's initialized. An example of exporting and importing might look like this:
// titleCase.cjs

function titleCase(str) {
   if (!str){
      return '';
   }
   return str.toLowerCase().split(' ').map(word => {
      if (!word){
         return word;  
      }else{
         return word.charAt(0).toUpperCase() + word.slice(1);
      }
   }).join(' ');
}

module.exports = titleCase;
// app.js

const titleCase = require('./titleCase');
console.log(titleCase('the good, the bad and the ugly'));

// "The Good, The Bad And The Ugly"
  1. ES modules use the import keyword to load modules and the export keyword to export them. They are static, so they need to be described at the top level of every module and support loading modules asynchronously. ES modules facilitate static analysis of the dependency tree, making dead code elimination (tree shaking) more efficient. The same titleCase function above using ESM would look like:
// titleCase.js

export default function titleCase(str) {
   if (!str){
      return '';
   }
   return str.toLowerCase().split(' ').map(word => {
      if (!word){
         return word;  
      }else{
         return word.charAt(0).toUpperCase() + word.slice(1);
      }
   }).join(' ');
}
// app.js

import titleCase from './titleCase.js'; //< File extension required on import
console.log(titleCase('the good, the bad and the ugly'));

// "The Good, The Bad And The Ugly"
  1. ES modules run implicitly in strict mode (can't be disabled). This is a good thing in many opinions as it enforces good coding practices.
  2. In CommonJS you can use the helpful __filename and __dirname. In ES modules you need to do a workaround to get the same functionality like so:
import { fileURLToPath } from 'url'
import { dirname } from 'path'
const __filename = fileURLToPath(import.meta.url)
const __dirname = dirname(__filename)
  1. You can dynamically load modules in CommonJS with require:
let usefulModule;
if (process.env.DEV === true) {
   usefulModule = require('./utils/devmodule')
} else {
   usefulModule = require('./utils/prodmodule')
}
  1. And in ESM by using import as function:
let lib;
if (process.env.DEV === true) {
   lib  = await import('./utils/devmodule.js');
} else {
   lib  = await import('./utils/prodmodule.js');
}
const usefulModule = lib.usefulModule;

One thing I have noticed over the years of programming is that languages and libraries evolve. I have observed a growing shift in Node package docs giving more and more of their examples in ESM format. CommonJS is still the dominant option on npm but it tells me the ecosystem is slowly shifting away from CommonJS and towards ESM. Maybe they will run in tandem but such is the nature of evolution, one becomes dominant over the others. All of the projects I work on use the ESM approach. Good luck deciding.

2 of 3
1

ES modules are designed to be loaded statically, while CommonJS modules are mainly loaded dynamically and synchronously. This can lead to slower performance and a blocking of the main thread. Static analysis refers to the process of analyzing code without executing it, and dynamic imports introduce runtime behavior into a module system. This means that the exact module that will be imported cannot be determined until the code is executed, making it difficult to analyze the module dependencies and relationships ahead of time (AOT).

Read this article please. https://dev.to/costamatheus97/es-modules-and-commonjs-an-overview-1i4b

🌐
Reddit
reddit.com β€Ί r/node β€Ί common js vs es modules and why?
r/node on Reddit: Common JS vs ES Modules and why?
December 9, 2022 -

Hey, I'm working on a small side project and learning node and just can't wrap my head around what's happening here. Please forgive if this has already been answered for someone else. I searched around and the answers don't quite do it for me.

My situation is this. I've installed create-react-app, graphql, and apollo client/server. I'm working on getting the server set up and through that have added a few lines to the server file that use an import statement.

The guide that I was following to set up the server however uses Common JS. This confuses me.

I don't understand why one is used over the either. I'm getting an error now when I init the server file that says "Cannot use import statement outside of a module". I understand that this means that the import statement isn't valid in my current file but I don't know why it's invalid in this file but perfectly fine in my react typescript files.

Can someone please explain to me why/when I should be using import vs. require, and why it only works in certain files and folders?

Thank you in advance!

Top answer
1 of 1
33
CommonJS is old, but Node tries to hold on to backwards compatibility as much as it can, but forward compatibility is a whole 'nother story. The major difference is, import is an asynchronous means of including modules, where as require is synchronous. CommonJS does not support async in the root of a module, import itself does exist in CommonJS, just not in the root level of a module (file). If you create an async function, you can all and await import from inside of it. ESM will handle the root level async imports for you, and provide a whole realm of future features going forward. ESM can consume and use CommonJS modules, but CommonJS cannot consume ESM modules, it's a one way street. A module either has to explicitly output both an ESM and a CommonJS output, and be configured in such a way that it exposes both in a resolvable fashion. In some cases people use a simple wrapper to achieve this, but it does not come without it's pains. This is mostly only an issue if you're building something with the intention of publishing it to npm where it will be consumed by a wider audience. Because whether or not you support both impacts who can consume your API. The reason you get this error: Cannot use import statement outside of a module Is because the backend project where you're using import is currently set to be CommonJS. You should add: { ... type: "module" ... } to your package.json in your backend project. If you'd like to see a TypeScript project configured to support both commonjs and ESM, without relying on any additional dependencies to do so, you can see my csrf-csrf project here, which has a package.json and a tsconfig, and some scripts, configured to output and publish a module to npm which natively supports both.
🌐
Syncfusion
syncfusion.com β€Ί blogs β€Ί javascript β€Ί commonjs vs es modules in javascript: core differences, practical use cases, and best practices
CommonJS vs ES Modules in JavaScript: Core Differences, Practical Use Cases, and Best Practices | Syncfusion Blogs
March 10, 2026 - Most developers think of the difference as require vs import, but the real story goes much deeper: how each module loads, how tools optimize them, and how painful it can be to mix both in a real project. Syncfusion JavaScript UI controls are the developers’ choice to build user-friendly web applications. You deserve them too. ... CommonJS is the module system that Node.js adopted as its default before ES Modules existed.
🌐
DEV Community
dev.to β€Ί costamatheus97 β€Ί es-modules-and-commonjs-an-overview-1i4b
ES Modules and CommonJS: An Overview - DEV Community
February 3, 2023 - ... // my-module.js module.exports = { myValue: 42 }; // main.js const myModule = require('./my-module.js'); console.log(myModule.myValue); // 42 Β· ES modules are a standardized module system for JavaScript that was introduced in ES6.
Find elsewhere
🌐
Full Stack Foundations
fullstackfoundations.com β€Ί blog β€Ί commonjs vs. es6 modules for beginners
CommonJS vs. ES6 Modules for Beginners
March 29, 2024 - Alongside this crazy idea of bringing JavaScript server-side was the concept of a "module system" called CommonJS (originally named ServerJS), which aimed to make it easier to split JS logic into multiple "modules" (in this context, synonymous with "files" since there is a 1:1 relationship between module:file).
🌐
Fireship
fireship.dev β€Ί javascript-modules-iifes-commonjs-esmodules
JavaScript Modules: From IIFEs to CommonJS to ES6 Modules
This is achieved by forcing modules to explicitly export those variables it wants to expose to the "universe", and also by defining those other modules required to properly work. ... If you've used Node before, CommonJS should look familiar. The reason for that is because Node uses (for the most part) the CommonJS specification in order to implement modules.
🌐
Better Stack
betterstack.com β€Ί community β€Ί guides β€Ί scaling-nodejs β€Ί commonjs-vs-esm
CommonJS vs. ES Modules | Better Stack Community
February 2, 2025 - Despite its popularity in Node.js, CommonJS has no static analysis, meaning tools cannot optimize code by removing unused functions (no tree shaking). It also relies on synchronous execution, which is inefficient for browser-based applications. These drawbacks led to the development of ECMAScript modules, which offers better performance and different syntax. ECMAScript modules were introduced in ES6 ...
🌐
freeCodeCamp
freecodecamp.org β€Ί news β€Ί modules-in-javascript
Modules in JavaScript – CommonJS and ESmodules Explained
September 11, 2024 - CommonJS is a set of standards used to implement modules on JavaScript.
🌐
SitePoint
sitepoint.com β€Ί blog β€Ί es6 β€Ί understanding es6 modules
Understanding ES6 Modules β€” SitePoint
November 13, 2024 - ES6 modules are pre-parsed in order to resolve further imports before code is executed. CommonJS modules load dependencies on demand while executing the code.
🌐
Medium
tianyaschool.medium.com β€Ί commonjs-vs-es6-modules-a-deep-dive-into-frontend-modularization-2acf6a783ec3
CommonJS vs. ES6 Modules β€” A Deep Dive into Frontend Modularization | by Kevin | Mar, 2026 | Medium
March 6, 2026 - Its synchronous loading suits server environments perfectly β€” modules load once at startup without complex async callback handling. Node.js’s ecosystem contains vast resources built on CommonJS, reducing development time and costs. In browser environments, ES6 modules have risen to prominence as frontend development’s β€œnew favorite.” They provide elegant, efficient solutions for browser-side modularization.
🌐
DEV Community
dev.to β€Ί saisathish β€Ί nodejs-modules-commonjs-vs-ecmascript-28da
Node.js Modules: CommonJS vs. ECMAScript - DEV Community
March 21, 2023 - ECMAScript modules, also known as ES modules, are a newer module system that was introduced in ECMAScript 6 (ES6). Unlike CommonJS, ES modules are asynchronous and use an import statement to load modules.
🌐
DEV Community
dev.to β€Ί stalwartcoder β€Ί es-modules-or-commonjs-whats-the-deal-and-why-should-i-care--3hem
ES Modules or CommonJS: What's the Deal and Why Should I Care ? - DEV Community
May 10, 2023 - Back in the day, JavaScript didn't have a built-in module system. So, dev's couldn't easily separate their code into different files or manage dependencies. It was kind of a mess. But then, Node.js stepped up with its own module system, CommonJS. And later, ES6 (ES2015) introduced ES Modules.
🌐
Medium
medium.com β€Ί computed-comparisons β€Ί commonjs-vs-amd-vs-requirejs-vs-es6-modules-2e814b114a0b
- β€” β€” β€” β€” CommonJS vs AMD vs RequireJS vs ES6 Modules β€” β€” β€” β€” - | by Mohanesh Sridharan | Computed Comparisons | Medium
November 8, 2018 - We tried to emulate a module system using the module pattern, CommonJS and AMD. Fortunately, ECMAScript 6 have introduced built-in modules which takes it through to the next and final section. ... ECMAScript 6 a.k.a., ES6 a.ka., ES2015 offers possibilities for importing and exporting modules compatible with both synchronous and asynchronous modes of operation.
🌐
DEV Community
dev.to β€Ί sudiip__17 β€Ί -commonjs-vs-es6-modules-understanding-cjs-and-mjs-in-nodejs-5e19
# CommonJS vs. ES6 Modules: Understanding CJS and MJS in Node.js - DEV Community
August 15, 2025 - The JavaScript modules tutorial landscape is shifting toward ES6 modules as the standard, but CommonJS remains widely used in existing codebases.
🌐
GreatFrontEnd
greatfrontend.com β€Ί questions β€Ί quiz β€Ί explain-the-differences-between-commonjs-modules-and-es-modules
Explain the differences between CommonJS modules and ES modules in JavaScript | Quiz Interview Questions with Solutions
September 5, 2021 - It uses the require() function to load modules and the module.exports or exports object to define the exports of a module. ... ES Modules (ECMAScript Modules) are the standardized module system introduced in ES6 (ECMAScript 2015).
🌐
Medium
medium.com β€Ί @laveshgaurav β€Ί javascript-modules-demystified-es6-modules-vs-commonjs-vs-amd-eb410ab25e70
JavaScript Modules Demystified: ES6 Modules vs CommonJS vs AMD | by Lavesh Gaurav | Medium
July 24, 2025 - ES6 Modules: The future. Use it for all modern JavaScript development. CommonJS: Still dominant in Node.js but gradually being phased out.