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.