Learn the concept
Modules
ES Modules use import/export syntax with static analysis and are asynchronously loaded. CommonJS uses require/module.exports with synchronous loading. ESM is the modern standard for browsers and modern Node.js, while CJS is the legacy Node.js module system.
ES Modules (ESM):
import / exportawait supportedthis is undefined at top level.mjs or "type": "module" in package.json<script type="module">)CommonJS (CJS):
require() / module.exportsthis is module.exports at top level.cjs or default in Node.jsKey differences: | Feature | ESM | CJS | |---------|-----|-----| | Syntax | import/export | require/module.exports | | Loading | Async | Sync | | Analysis | Static (tree-shakeable) | Dynamic | | Browser | Native support | Needs bundler | | Node.js | Supported (all current versions) | Default (legacy) |
Note: Node.js 22.12+ supports require(esm) by default, allowing CJS code to import ES modules directly.
// Named exports
export const PI = 3.14;
export function add(a, b) { return a + b; }
// Default export
export default class Calculator { /* ... */ }
// Importing
import Calculator, { PI, add } from './math.js';
import * as math from './math.js';
// Dynamic import (code splitting)
const module = await import('./heavy-module.js');
// Re-exporting
export { add } from './math.js';
export { default as Calculator } from './calc.js';Shipping npm packages with both ESM and CJS builds using package.json exports for maximum compatibility
Using dynamic import() to load features on demand in SPAs, reducing initial bundle size
Sharing modules across packages in a monorepo using workspace imports with proper ESM/CJS resolution
Create an npm package that exports both ESM and CJS using package.json conditional exports field
Build a plugin system using dynamic import() to load modules at runtime based on configuration