← CodeClarityLab Home
Browse by Category
+ added · updated 7d
← Back to glossary

ES Modules (ESM)

javascript ES2015 Intermediate

Also Known As

ES modules ESM import/export JavaScript modules native modules

TL;DR

The official JavaScript module system — import and export statements enable static dependency graphs, tree-shaking, and native browser module loading without a bundler.

Explanation

ES Modules (ESM), standardised in ES2015, replaced the CommonJS require/module.exports pattern. Named exports (export const x = ...) and default exports (export default ...) are imported with import { x } from './mod.js' and import Foo from './mod.js' respectively. ESM is statically analysed — imports are resolved at parse time, not runtime, enabling bundlers to tree-shake unused exports. In browsers, <script type="module"> loads ESM natively with automatic defer semantics and strict mode. In Node.js, ESM files use .mjs extension or "type": "module" in package.json. Key differences from CommonJS: ESM imports are live bindings (reflect mutations in the exporting module), CJS exports are copied values. Dynamic import() returns a Promise and enables code-splitting — loading a module on demand rather than at startup. Import maps (supported in modern browsers) allow remapping bare specifiers like 'react' to a CDN URL without a bundler.

Watch Out

Node.js does not allow require() inside ESM modules — if a dependency is CJS-only, you must use dynamic import() or stay in CJS. The error 'require is not defined in ES module scope' is a common migration surprise.

Common Misconception

ESM imports are live bindings — if the exporting module later mutates an exported variable, the importing module sees the updated value. This is the opposite of CommonJS, which copies the value at require() time.

Why It Matters

ESM is the foundation of modern JavaScript tooling — tree-shaking, code splitting, and native browser loading all depend on ESM's static structure. Mixing CJS and ESM in Node.js projects is a frequent source of confusing errors.

Common Mistakes

  • Omitting the file extension in Node.js ESM imports — 'import x from './utils'' fails; the extension '.js' is required (no automatic resolution).
  • Using require() in a .mjs file or a package with type:module — CJS and ESM cannot be mixed without dynamic import().
  • Re-exporting a default as a named export — import Foo from './a'; export { Foo } is needed; export { default } from './a' is the cleaner form.
  • Expecting top-level this to be the module object — in ESM, top-level this is undefined (strict mode), not the global or module object.

Code Examples

💡 Note
The CJS version loads the entire date-fns library at runtime; the ESM version lets bundlers include only the format function. In the browser, <script type="module"> defers automatically and scopes the module — no global pollution.
✗ Vulnerable
// CommonJS — no tree-shaking, runtime resolution:
const { format } = require('date-fns');
module.exports = { formatDate };
✓ Fixed
// ESM — statically analysable, tree-shakeable:
import { format } from 'date-fns'; // bundler can drop unused date-fns exports

export function formatDate(date) {
    return format(date, 'yyyy-MM-dd');
}
// In Node.js: file must be .mjs or package.json must have "type": "module"

Added 10 Apr 2026
Views 22
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings W 0 pings T 0 pings F 0 pings S 0 pings S 1 ping M 0 pings T 0 pings W 0 pings T 1 ping F 0 pings S 2 pings S 0 pings M 0 pings T 0 pings W 0 pings T 1 ping F 1 ping S 0 pings S 0 pings M 0 pings T 0 pings W 1 ping T 0 pings F 1 ping S 1 ping S 0 pings M 0 pings T 0 pings W 0 pings T
No pings yet today
No pings yesterday
Perplexity 3 SEMrush 3 Google 2 ChatGPT 1 Unknown AI 1 Ahrefs 1 Qwen 1
crawler 11 crawler_json 1
DEV INTEL Tools & Severity
🟢 Low ⚙ Fix effort: Medium
⚡ Quick Fix
Add "type":"module" to package.json, rename .js to .mjs or update imports to include .js extensions
🔗 Prerequisites
🔍 Detection Hints
require( or module.exports in a file with .mjs extension or in a package with type:module
Auto-detectable: ✓ Yes eslint typescript
⚠ Related Problems
🤖 AI Agent
Confidence: High False Positives: Low ✗ Manual fix Fix: Medium Context: File Tests: Update

✓ schema.org compliant