On this page
ES Modules and Module Patterns
Modules organize code into reusable files with explicit dependencies and encapsulated scope.
ES Modules (ESM)
Each module has its own scope. Use export and import:
// math.js
export const PI = 3.14159;
export function add(a, b) { return a + b; }
export default function multiply(a, b) { return a * b; }
// app.js
import multiply, { PI, add } from './math.js';
console.log(add(2, 3)); // 5
console.log(multiply(2, 3)); // 6
Named re-export
// index.js — barrel file
export { add, multiply } from './math.js';
export * from './utils.js';
Import aliases
import { add as sum } from './math.js';
import * as MathUtils from './math.js';
Dynamic Import
Load modules on demand (returns a Promise):
button.addEventListener('click', async () => {
const module = await import('./heavy-feature.js');
module.init();
});
Useful for code splitting and lazy loading routes.
CommonJS (Node.js)
Legacy Node.js module system:
// math.cjs
const PI = 3.14159;
function add(a, b) { return a + b; }
module.exports = { PI, add };
// app.cjs
const { add, PI } = require('./math.cjs');
Modern Node.js supports both ESM (.mjs or "type": "module" in package.json) and CommonJS.
ESM vs CommonJS
| Feature | ESM | CommonJS |
|---|---|---|
| Syntax | import/export |
require/module.exports |
| Loading | Static (analyzed at parse time) | Dynamic (runtime) |
| Tree shaking | Yes | Limited |
| Browser | Native support | Needs bundler |
| Node.js | Supported (v12+) | Default in older Node |
Module Scope
Top-level variables are module-scoped, not global:
// counter.js
let count = 0;
export function increment() { return ++count; }
// Each import gets live bindings to exports
Circular Dependencies
ESM handles circular imports better than CommonJS, but design modules to minimize cycles.
IIFE Module Pattern (Legacy)
Before ES modules:
const MyModule = (function() {
let private = 0;
return {
get() { return private; },
set(v) { private = v; }
};
})();
package.json for Node ESM
{
"type": "module",
"exports": {
".": "./src/index.js",
"./utils": "./src/utils.js"
}
}
Bundlers
Tools like Vite, Webpack, and Rollup bundle ESM for browsers and optimize with tree shaking:
// Only imported exports are included in bundle
import { debounce } from 'lodash-es';
Use ES modules for all new JavaScript projects — they are the standard across browsers and Node.js.