AMD
Asynchronous Module Definition. A pre-ESM module format designed for browsers, used with RequireJS. Modules declare dependencies as an array and receive them as callback arguments. Largely obsolete, replaced by ES Modules.
Bare Specifier
A module import path that does not start with ./, ../, or /. Examples: 'lodash', 'react'. Browsers cannot resolve these natively - they require import maps or a bundler.
Barrel File
An index.js file that re-exports from multiple other modules, providing a single entry point: export { foo } from './foo.js'. Convenient but can harm tree-shaking and increase bundle size if not handled carefully.
Bundler
A tool that combines multiple module files into one or more output files for deployment. Examples: Rollup, webpack, esbuild, Vite (uses Rollup), Rspack. Bundlers resolve imports, perform tree-shaking, and optimize output.
Circular Dependency
When module A imports from module B and module B imports from module A (directly or through a chain). ES Modules handle this via live bindings, but circular dependencies can cause variables to be undefined during initialization.
CommonJS
The module system used by Node.js since 2009. Uses require() for imports and module.exports for exports. Synchronous loading, value copies (not live bindings), dynamic structure. Being gradually replaced by ESM.
Conditional Export
A package.json "exports" field that maps different entry points based on conditions like "import", "require", "browser", or "default". Allows packages to serve different code to ESM and CJS consumers.
Dead Code Elimination
The process of removing code that is never executed or referenced from the final output. Tree-shaking is a specific form of dead code elimination that operates at the module export level. Enabled by ESM's static structure.
Default Export
A module's primary export, declared with export default. Each module can have at most one default export. Importers can choose any local name: import anything from './mod.js'.
Deferred Evaluation
A pattern or proposal (TC39 Stage 3: import defer) where a module's code is not executed until one of its exports is first accessed. Reduces startup cost for modules that may not be needed immediately.
Dynamic Import
Loading a module at runtime using import('./module.js'), which returns a Promise. Unlike static imports, dynamic imports can use computed paths and appear inside conditionals, loops, or functions. Used for code splitting and lazy loading.
Entry Point
The starting module that a bundler or runtime begins loading from. All other modules are discovered by following its import statements. In package.json, defined by "main", "module", or "exports" fields.
ES Module
The official JavaScript module system standardized in ECMAScript 2015. Uses import and export syntax, provides live bindings, enforces strict mode, supports static analysis, and works in browsers, Node.js, Deno, and Bun.
Export Map
The "exports" field in package.json that defines which module entry points a package exposes. Controls what consumers can import and enables conditional exports for different environments (ESM, CJS, browser, Node.js).
Import Attributes
A syntax for providing metadata about imports using the with keyword: import data from './data.json' with { type: 'json' }. Standardized in ES2025. Used for JSON modules, CSS modules, and future non-JavaScript module types.
Import Map
A JSON configuration in a <script type="importmap"> tag that tells the browser how to resolve bare specifiers. Maps package names to URLs, enabling bundler-free development. Supported in all modern browsers.
Import Specifier
The string that identifies the module to import. Three types: relative ('./utils.js'), absolute ('https://cdn.example.com/lib.js'), and bare ('lodash'). Each resolves differently depending on the environment.
JSON Module
A JSON file imported as an ES Module: import config from './config.json' with { type: 'json' }. The JSON data becomes the module's default export. Requires import attributes for security (prevents MIME type confusion attacks).
Live Binding
An ES Module feature where imported bindings are references to the exporting module's variables, not copies. If the exporting module changes a value, all importers see the update immediately. This is fundamentally different from CommonJS value copying.
Loader
The runtime mechanism that fetches, parses, and evaluates modules. Browsers use the HTML spec's module loader; Node.js has its own loader with hooks for customization (--loader flag). Loaders handle URL resolution, file fetching, and module caching.
Module Graph
The dependency tree formed by all import relationships starting from an entry point. The runtime builds this graph by analyzing static imports before executing any module code. The graph determines evaluation order and enables optimizations.
Module Record
The internal representation of a parsed module in the JavaScript engine. Contains the module's source text, import/export entries, requested modules, and evaluation status. Each module URL has exactly one Module Record (singleton).
Module Scope
Each ES Module has its own top-level scope - variables declared at the top level are not added to the global object. This eliminates global pollution. Only explicitly exported values are accessible to other modules.
Named Export
An export with a specific identifier: export function add() {} or export { add }. Must be imported by the exact name (with optional renaming via as). A module can have any number of named exports.
Namespace Import
Importing all exports of a module as a single object: import * as utils from './utils.js'. The namespace object has properties for each named export and a default property for the default export. Always a live, read-only object.
Package Exports
The "exports" field in package.json (Node.js 12.7+). Defines the public API of a package, restricts access to internal files, and supports subpath exports ("./utils") and conditional exports ("import"/"require").
Re-export
Exporting something that was imported from another module: export { foo } from './other.js'. The re-exporting module never has a local binding to the value. Used in barrel files and to create public API surfaces.
Resolution Algorithm
The process of converting a module specifier to an absolute URL or file path. Browsers resolve relative to the importing module's URL. Node.js checks package.json exports, then node_modules. Import maps customize browser resolution.
Side Effects
Code that executes at module evaluation time and affects state outside the module (DOM manipulation, global variable assignment, polyfills). The "sideEffects": false field in package.json tells bundlers it is safe to tree-shake unused modules entirely.
Source Phase Import
A TC39 proposal (import source mod from './module.wasm') that gives access to a module's source representation (like a WebAssembly.Module) without evaluating it. Enables compiling and instantiating WebAssembly modules with custom imports.
Static Analysis
Analyzing code without executing it. ES Module imports/exports are static (determinable at parse time), unlike CommonJS require() which can be dynamic. Static analysis enables tree-shaking, type checking, and IDE autocompletion.
Subpath Import
The "imports" field in package.json that creates private import aliases within a package: "#utils": "./src/utils.js". Only usable within the package itself. Useful for mapping platform-specific implementations.
Top-Level Await
Using await at the module's top level without wrapping it in an async function: const data = await fetch('/api'). Standardized in ES2022. The importing module waits for the awaited promise to resolve before executing.
Tree-Shaking
A bundler optimization that removes unused exports from the final output. Named after "shaking a tree" to remove dead leaves. Only possible with ES Modules because their static structure allows bundlers to determine what is used at build time.
UMD
Universal Module Definition. A wrapper pattern that makes a module work in AMD, CommonJS, and browser globals. Characterized by a boilerplate IIFE that detects the environment. Still used by some libraries for maximum backward compatibility.
A named export uses a specific identifier (export function foo()) and must be imported by that exact name using destructuring (import { foo }). A default export (export default function()) allows the importer to choose any name (import myFoo). A module can have multiple named exports but only one default export.
Tree-shaking is a dead code elimination technique that removes unused exports from the final bundle. It works because ES Module imports and exports are static - analyzable at build time without running the code. Bundlers like Rollup, Vite, and webpack can determine which exports are actually used and exclude everything else.
A bare specifier is a module path that does not start with './', '../', or '/' - for example, import lodash from 'lodash'. Browsers cannot resolve bare specifiers natively. Import maps solve this by mapping bare specifiers to actual URLs, while bundlers and Node.js resolve them via the node_modules directory.
Live bindings mean that when a module exports a variable and later changes its value, all importing modules see the updated value immediately. This is different from CommonJS, which copies values at require() time. Live bindings enable patterns like shared counters and reactive state without event systems.