JavaScript Modules
This lesson explains JavaScript Modules with clear examples, use cases, and best practices so you can use modern JavaScript confidently in real projects.
ES6+ JavaScript Modules Overview
ES6 modules let you split JavaScript code into separate files that
export and import functionality. Each module has its own scope, which
helps you build larger applications without polluting the global
namespace.
Modern tools and frameworks such as React, Vue, Angular, Node.js,
Vite, and Astro rely on ES modules to organize code, improve
maintainability, and enable features like tree shaking and code
splitting.
| Feature | Description |
| Introduced In | ES6 (ECMAScript 2015) |
| Keywords | export and import |
| Scope | Module scope, not global scope |
| Strict Mode | Enabled automatically in modules |
| Browser Usage | <script type="module"> |
| Common Uses | Utilities, components, services, config files |
Basic Module Example
// math.js
export function add(a, b) {
return a + b;
}
export const PI = 3.14159;
// app.js
import { add, PI } from "./math.js";
console.log(add(4, 6));
console.log(PI);
One file exports values, and another file imports them. This is the
foundation of modular JavaScript architecture.
How JavaScript Modules Work
A module is simply a JavaScript file that can expose selected values
and use values from other files through a standard import/export
system.
| Step | Description | Example |
| Create Module File | Put related code in its own file. | utils.js |
| Export Values | Expose functions, constants, or classes. | export function ... |
| Import Elsewhere | Bring exported values into another file. | import { ... } |
| Use Module Scope | Keep internal code private by default. | Non-exported variables stay local |
| Build Application | Combine many modules into one app. | Components, services, helpers |
Module Scope and Privacy
// counter.js
let count = 0;
export function increment() {
count += 1;
return count;
}
export function getCount() {
return count;
}
// main.js
import {
increment,
getCount
} from "./counter.js";
console.log(increment());
console.log(getCount());
// count is not accessible here directly
Variables that are not exported remain private to the module. This
helps prevent accidental global state and naming conflicts.
Using Modules in the Browser
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>ES Modules</title>
</head>
<body>
<script type="module" src="./app.js"></script>
</body>
</html>
Browsers load ES modules when the script tag includes
type="module". Module scripts are deferred by default
and run after the HTML document is parsed.
Typical Module File Structure
project/
src/
utils/
formatDate.js
validateEmail.js
services/
api.js
auth.js
components/
Header.js
Footer.js
app.js
index.html
Modules encourage organizing code by responsibility. Utility
functions, API services, and UI components each live in focused
files that are easier to test and maintain.
Default Export Preview
// logger.js
export default function log(message) {
console.log(`[LOG] ${message}`);
}
// app.js
import log from "./logger.js";
log("Application started");
A module can have one default export and multiple named exports.
The next lesson covers export and import patterns in more detail.
Modules vs Classic Scripts
| Feature | ES Module | Classic Script |
| Scope | Module scope | Global or function scope |
| Strict Mode | Always enabled | Optional |
| Import/Export | Supported | Not supported natively |
| Browser Attribute | type="module" | Default script tag |
| Loading | Deferred by default | Blocking unless deferred |
ES Modules vs CommonJS
// ES Module
export function greet(name) {
return `Hello ${name}`;
}
import { greet } from "./greet.js";
// CommonJS
function greet(name) {
return `Hello ${name}`;
}
module.exports = { greet };
const { greet } = require("./greet");
ES modules use import and export, while
CommonJS uses require() and
module.exports. Modern frontend tools and current
Node.js projects increasingly prefer ES modules.
Why Use ES Modules?
- Split large applications into smaller reusable files.
- Avoid polluting the global
window object. - Improve code organization and maintainability.
- Enable tree shaking in modern bundlers.
- Support lazy loading and code splitting.
- Make testing and refactoring easier.
- Work naturally with modern frameworks and build tools.
Common Module Use Cases
- Utility helper files such as formatters and validators.
- API and authentication service modules.
- Reusable UI components in frontend apps.
- Configuration and constants files.
- Feature-based folders in large applications.
- Shared business logic across multiple pages.
- Library and package development.
JavaScript Module Best Practices
- Keep each module focused on one responsibility.
- Use clear file names such as
auth.js or formatDate.js. - Export only what other files need.
- Prefer many small modules over one huge file.
- Use explicit import paths in browser module projects.
- Include file extensions such as
.js in browser imports when required. - Organize modules by feature or domain, not only by file type.
Common Module Mistakes
- Forgetting
type="module" in browser script tags. - Trying to use
import in a non-module script. - Expecting non-exported variables to be available globally.
- Mixing ES modules and CommonJS without understanding compatibility.
- Creating circular dependencies between modules.
- Putting too much unrelated code in one module file.
- Using incorrect relative import paths between files.
Key Takeaways
- ES6 modules split JavaScript into reusable files with import/export syntax.
- Each module has its own scope and runs in strict mode.
- Browsers load modules with
type="module". - Modules improve organization, privacy, and maintainability.
- Export and import patterns are covered in the next lesson.
Pro Tip
Think of each module as a small package: export the public API,
keep internal helpers private, and import only what each file needs.