ES Modules in Node.js
While CommonJS has been the traditional module system in Node.js, JavaScript now has a standard module system called **ES Modules (ESM)**. It uses `import` and `export` keywords and is the official standard for JavaScript modules.
CommonJS vs ES Modules
| Aspect | CommonJS | ES Modules |
|---|---|---|
| Syntax | `require()` / `module.exports` | `import` / `export` |
| Loading | Synchronous | Asynchronous |
| File Extension | `.js` (default) | `.mjs` or `"type": "module"` in package.json |
| Top-level `this` | `module.exports` | `undefined` |
| Dynamic imports | `require()` anywhere | `import()` function |
Think of ES Modules as the modern, standardized way to organize code – like upgrading from VHS to Blu-ray.
Enabling ES Modules in Node.js
There are two ways to tell Node.js to use ES Modules:
- Use the `.mjs` file extension.
- Set `"type": "module"` in your `package.json` (then `.js` files are treated as ES modules).
package.json
{ "name": "my-esm-project", "version": "1.0.0", "type": "module", "scripts": { "start": "node index.js" }}Exporting with ES Modules
math.mjs
<!-- Named exports -->export const add = (a, b) => a + b;export const subtract = (a, b) => a - b;
<!-- Default export -->const multiply = (a, b) => a * b;export default multiply;
<!-- Export all at once -->const pi = 3.14159;const e = 2.71828;export { pi, e };Importing with ES Modules
app.mjs
<!-- Import named exports -->import { add, subtract, pi, e } from './math.mjs';
console.log(add(5, 3)); <!-- 8 -->console.log(pi); <!-- 3.14159 -->
<!-- Import default export -->import multiply from './math.mjs';console.log(multiply(4, 3)); <!-- 12 -->
<!-- Import all as an object -->import * as math from './math.mjs';console.log(math.add(10, 5)); <!-- 15 -->Dynamic Imports
ES Modules support dynamic imports using `import()` – which returns a promise. This is useful for code splitting or loading modules conditionally.
async function loadModule(moduleName) { try { const module = await import(`./${moduleName}.mjs`); console.log(module.add(2, 3)); } catch (err) { console.error('Failed to load module', err); }}
loadModule('math');Important Differences
1. No `__dirname` or `__filename`
In ES Modules, `__dirname` and `__filename` are not available. Instead, use:
import { fileURLToPath } from 'url';import { dirname } from 'path';
const __filename = fileURLToPath(import.meta.url);const __dirname = dirname(__filename);2. JSON Imports
In ES Modules, you need to use assertion syntax to import JSON:
import data from './data.json' assert { type: 'json' };3. Top-level `await`
In ES Modules, you can use `await` at the top level without wrapping in an async function.
import fs from 'fs/promises';
const data = await fs.readFile('file.txt', 'utf8');console.log(data);Two Minute Drill
- ES Modules are the official JavaScript module standard using `import`/`export`.
- Enable them with `.mjs` extension or `"type": "module"` in package.json.
- Supports named exports, default exports, and dynamic imports.
- `__dirname` and `__filename` are not available – use `import.meta.url`.
- Top-level `await` is allowed in ES Modules.
Need more clarification?
Drop us an email at career@quipoinfotech.com
