JavaScript modules: import/export, CommonJS vs es modules
What are JavaScript Modules?
Modules allow you to split code into separate files, each with its own scope. They help organize code, prevent naming conflicts, and enable reusability.
ES Modules (ESM)
The modern standard, supported in browsers and Node.js.
Named Exports
javascript
// math.js
export const PI = 3.14159;
export function add(a, b) { return a + b; }
export function multiply(a, b) { return a * b; }
// main.js
import { PI, add, multiply } from './math.js';
import { add as sum } from './math.js'; // rename
import * as math from './math.js'; // namespace importDefault Export
javascript
// User.js
export default class User {
constructor(name) { this.name = name; }
}
// main.js
import User from './User.js'; // any name works
import MyUser from './User.js'; // same thingMixed Exports
javascript
// api.js
export const BASE_URL = "/api";
export default function fetchData(endpoint) {
return fetch(BASE_URL + endpoint);
}
// main.js
import fetchData, { BASE_URL } from './api.js';Re-exporting
javascript
// index.js (barrel file)
export { default as User } from './User.js';
export { default as Product } from './Product.js';
export * from './utils.js';CommonJS (CJS)
The Node.js module system (before ES modules):
javascript
// math.js
const PI = 3.14159;
function add(a, b) { return a + b; }
module.exports = { PI, add };
// or: exports.PI = PI;
// main.js
const { PI, add } = require('./math');
const math = require('./math');ESM vs CommonJS Comparison
| Feature | ES Modules | CommonJS |
|---|---|---|
| Syntax | import/export | require()/module.exports |
| Loading | Static (compile-time) | Dynamic (runtime) |
| Top-level await | Yes | No |
| Tree shaking | Yes | No |
| Browser support | Yes (native) | No (needs bundler) |
| Node.js | .mjs or "type": "module" | Default in Node.js |
| Hoisting | Imports are hoisted | Not hoisted |
Dynamic Imports
javascript
// Load module on demand (code splitting)
const module = await import('./heavyModule.js');
module.doSomething();
// Conditional loading
if (condition) {
const { feature } = await import('./feature.js');
feature();
}
// React lazy loading
const LazyComponent = React.lazy(() => import('./Component'));Module Scope
Each module has its own scope — variables declared in a module are not global:
javascript
// counter.js
let count = 0;
export const increment = () => ++count;
export const getCount = () => count;
// main.js
import { increment, getCount } from './counter.js';
increment(); // count is 1, but only inside counter.jsImportant:
Use ES Modules for all modern projects. They enable tree shaking (removing unused code), static analysis, and are the standard. Use dynamic import() for code splitting and lazy loading.
Short Answer
Interview readyPremium
A concise answer to help you respond confidently on this topic during an interview.