Suggest an editImprove this articleRefine the answer for “CommonJS vs ES Modules”. Your changes go to moderation before they’re published.Approval requiredContentWhat you’re changing🇺🇸EN🇺🇦UAPreviewTitle (EN)Short answer (EN)**CommonJS** (`require`/`module.exports`) loads modules synchronously and copies values at import time; **ES Modules** (`import`/`export`) load statically, asynchronously, and give you live bindings to the exported values. **Key point:** ESM supports tree-shaking and top-level await because its imports are static and known before the code even runs.Shown above the full answer for quick recall.Answer (EN)Image## 1. What CommonJS and ES Modules are | Module system | Where it came from | Key goal | |---|---|---| | **CommonJS (CJS)** | Node.js (2009) | Let server-side JavaScript use modules | | **ES Modules (ESM)** | The ECMAScript standard (ES6, 2015) | Create a native module system for JS (browsers + Node.js) | ## 2. Syntax ### CommonJS: ```javascript // math.js const PI = 3.14; function add(a, b) { return a + b; } module.exports = { PI, add }; // main.js const math = require('./math'); console.log(math.add(2, 3)); // 5 ``` Uses: - `require()` for importing modules - `module.exports` / `exports` for exporting modules ### ES Modules: ```javascript // math.mjs export const PI = 3.14; export function add(a, b) { return a + b; } // main.mjs import { add } from './math.mjs'; console.log(add(2, 3)); // 5 ``` Uses: - `import` / `export`, keywords from the ES6 standard - Supported natively by the browser and Node.js (with the right setup) ## 3. Main differences | # | Criterion | CommonJS (CJS) | ES Modules (ESM) | |---|---|---|---| | 1 | **Syntax** | `require`, `module.exports` | `import`, `export` | | 2 | **Module loading** | Dynamic (at runtime) | Static (at parse time) | | 3 | **Import type** | A copy of the value (by value) | A live binding (by reference) | | 4 | **Asynchrony** | Synchronous loading | Asynchronous loading | | 5 | **Top-level await** | no | yes | | 6 | **`this` context** | `this` points to `module.exports` | `this` is `undefined` (strict mode) | | 7 | **Module caching** | Yes (loaded once) | Yes, but with a different mechanism | | 8 | **Support in Node.js** | The default (`.js`) | Requires `"type": "module"` or the `.mjs` extension | | 9 | **Compatibility** | Older packages (npm, Express, etc.) | The newer ECMAScript standard | | 10 | **Use in the browser** | no (Node.js only) | yes (in `<script type="module">`) | ## 4. Static vs dynamic loading - **CommonJS:** Modules load **at runtime**, `require()` can be called anywhere: ```javascript if (condition) { const utils = require('./utils'); } ``` - **ES Modules:** Imports are **static**, they must sit **at the top of the file**: ```javascript import utils from './utils.js'; // cannot be inside an if ``` This lets ESM: - do **tree-shaking** (dropping unused code); - optimize bundling and execution. ## 5. Live bindings ES Modules support **live bindings**: if a value in the module changes, the import sees the change too. ### ESM: ```javascript // counter.mjs export let count = 0; export function increment() { count++; } // main.mjs import { count, increment } from './counter.mjs'; increment(); console.log(count); // 1 (updated) ``` ### CJS: ```javascript // counter.js let count = 0; function increment() { count++; } module.exports = { count, increment }; // main.js const { count, increment } = require('./counter'); increment(); console.log(count); // 0 (a copied value) ``` ## 6. Support in Node.js ### CommonJS: on by default `.js` files are treated as CommonJS unless `"type": "module"` is set. ### ES Modules: must be turned on explicitly Two ways: 1. In `package.json`: ```javascript { "type": "module" } ``` → then every `.js` file is treated as ESM. 2. Or use the `.mjs` extension: ```javascript node main.mjs ``` ## 7. An example of mixed code ### Importing CommonJS from ESM: ```javascript // ESM import pkg from './math.cjs'; console.log(pkg.add(2, 3)); ``` ### Importing ESM from CommonJS: ```javascript // CJS (async () => { const { add } = await import('./math.mjs'); console.log(add(2, 3)); })(); ``` Note: from CJS, importing ESM is **only possible asynchronously**, via `import()`. ## 8. `this` context and global variables | Feature | CommonJS | ES Modules | |---|---|---| | `this` | Points to `module.exports` | `undefined` | | Global objects | `__dirname`, `__filename`, `require`, `module`, `exports` | absent (can be obtained via `import.meta.url`) | ## 9. Support in npm packages - Older packages (`express`, `mongoose`, `chalk@4`), CommonJS. - Newer ones (`chalk@5`, `node-fetch`, `axios@next`), ES Modules. Mixing the two often causes errors: ```javascript Error [ERR_REQUIRE_ESM]: Must use import to load ES Module ``` ## 10. A summary comparison table | Characteristic | CommonJS | ES Modules | |---|---|---| | File format | `.js` | `.mjs` / `.js` with `"type": "module"` | | Import | `require()` | `import` | | Export | `module.exports` | `export` | | Loading | Synchronous | Asynchronous | | Binding type | Copy | Live binding | | `this` context | `module.exports` | `undefined` | | Browsers | no | yes | | Tree-shaking | no | yes | | Top-level await | no | yes | | Compatibility | Older packages | The newer standard | ## In short: > **CommonJS** is the older, synchronous, Node.js-specific module system. > **ES Modules** is the modern, standard, cross-platform format supported by both Node.js and browsers.For the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.