Before ES modulesWhat is es modules?The official JavaScript module standard using import and export - enabled in Node.js via "type": "module" in package.json., organizing JavaScript meant dumping everything into the global scopeWhat is scope?The area of your code where a variable is accessible; variables declared inside a function or block are invisible outside it. and hoping nothing collided. All variables shared one namespace, script load order mattered, and debugging name clashes felt like detective work. ES modules give JavaScript a proper moduleWhat is module?A self-contained file of code with its own scope that explicitly exports values for other files to import, preventing name collisions. system where every file has its own scope and explicit connections to other files.
Why modules matter
Think of modules as separate rooms in a house. Each room has its own furniture (variables), its own purpose (functionality), and doors (exports/imports) that connect them. Without modules, everything sits in one giant room where the kitchen table blocks the bedroom door.
<!-- The old way - order matters, everything is global -->
<script src="utils.js"></script>
<script src="api.js"></script>
<script src="app.js"></script>If utils.js and api.js both define a config variable, the last one loaded wins silently. Modules eliminate this entire category of bugs.
require() / module.exports) and ES module (import / export) syntax in the same file. This will not work, a file is either one system or the other. If you see const x = require('./file') next to export function y(), the AI has blended two incompatible module systems. Pick one and be consistent across your project. AI also generates wrong import paths, always verify the path matches your actual file structure.Exporting code
The export keyword makes values available to other files. There are two flavors.
Named exports
Named exports let you share multiple values from a single file. Consumers must use the exact name (or rename with as).
// math.js
export const PI = 3.14159;
export const E = 2.71828;
export function add(a, b) {
return a + b;
}
export function subtract(a, b) {
return a - b;
}You can also group exports at the bottom of the file:
// math.js (alternative style)
const PI = 3.14159;
function add(a, b) { return a + b; }
export { PI, add };Default exports
Each moduleWhat is module?A self-contained file of code with its own scope that explicitly exports values for other files to import, preventing name collisions. can have exactly one default exportWhat is default export?A module's single primary export, imported without curly braces and with any local name the caller chooses.. This is typically the "main thing" the module provides.
// UserService.js
export default class UserService {
constructor(apiUrl) {
this.apiUrl = apiUrl;
}
async getUser(id) {
const response = await fetch(`${this.apiUrl}/users/${id}`);
return response.json();
}
}Importing code
The import syntax changes depending on what you are importing.
// Named imports - curly braces required
import { PI, add } from './math.js';
// Default import - no braces
import UserService from './UserService.js';
// Namespace import - everything as one object
import * as MathUtils from './math.js';
// Combined - default + named together
import UserService, { validateUser } from './UserService.js';| Import style | Syntax | When to use |
|---|---|---|
| Named | import { x } from './file.js' | Importing specific values |
| Default | import x from './file.js' | Importing the main export |
| Namespace | import * as X from './file.js' | Importing everything as an object |
| Rename | import { x as y } from './file.js' | Avoiding name collisions |
ModuleWhat is module?A self-contained file of code with its own scope that explicitly exports values for other files to import, preventing name collisions. scopeWhat is scope?The area of your code where a variable is accessible; variables declared inside a function or block are invisible outside it. and strict mode
Modules automatically run in strict mode. Each module has its own top-level scope, variables declared at the top level are not global.
// utils.js
const secret = 'module-private';
// Not available to other files unless exported
export function useSecret() {
return secret;
}Real-world patterns
Barrel exports
An index.js file that re-exports from multiple modules in one place:
// components/index.js
export { Button } from './Button.js';
export { Card } from './Card.js';
export { Input } from './Input.js';
// Consumer imports from one location
import { Button, Card, Input } from './components/index.js';Dynamic imports
Load modules on demand for code splittingWhat is code splitting?Breaking your application into smaller JavaScript chunks that load on demand so users only download the code needed for the page they're viewing.:
async function showChart() {
const { Chart } = await import('./chartLibrary.js');
new Chart(data).render();
}Dynamic imports return a PromiseWhat is promise?An object that represents a value you don't have yet but will get in the future, letting your code keep running while it waits. and are great for loading heavy code only when the user actually needs it.
ModuleWhat is module?A self-contained file of code with its own scope that explicitly exports values for other files to import, preventing name collisions. paths
Always include the file extension in imports. Relative paths start with ./ or ../. Build tools may support aliases like @/.
import { helper } from './utils.js'; // Same directory
import { config } from '../config.js'; // Parent directory
import { theme } from '@/styles/theme.js'; // Alias (build tool)CommonJSWhat is commonjs?Node.js's original module format using require() and module.exports - distinct from and predating the ES module import/export syntax. vs ES modulesWhat is es modules?The official JavaScript module standard using import and export - enabled in Node.js via "type": "module" in package.json.
You will encounter both systems. Knowing the difference prevents confusion when AI tools mix them up.
| Feature | CommonJS (require) | ES Modules (import) |
|---|---|---|
| Syntax | const x = require('./file') | import x from './file.js' |
| Export | module.exports = x | export default x |
| Loading | Synchronous | Asynchronous |
| Environment | Node.js (default) | Browsers + Node.js |
| Tree shaking | No | Yes (unused code removed) |
Quick reference
| Syntax | What it does | Example |
|---|---|---|
export const x | Named export | export const PI = 3.14 |
export default x | Default export | export default class App {} |
import { x } | Import named | import { PI } from './math.js' |
import x | Import default | import App from './App.js' |
import * as X | Import namespace | import * as utils from './utils.js' |
import { x as y } | Rename import | import { PI as pi } from './math.js' |
export { x } from | Re-export | export { Button } from './Button.js' |