Skip to content

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.