Skip to content

ES Modules

  • ECMAScript Modules (ESM) are JavaScript’s built-in way to organize and structure your code into reusable pieces.
  • Introduced in ES6 (2015), modules let you break your code into smaller, focused files that can be imported and reused across your entire application.
  • Think of modules like building blocks: instead of writing all your code in one giant file, you can create separate, reusable files for different features and connect them together wherever you need them.
    • This promotes code reuse: write once, use everywhere.

Modules help you write better code by providing:

  • Code Reuse: Write a function, class, or variable once in a module, then import and reuse it anywhere in your application - or even across multiple projects. This eliminates code duplication and ensures consistency.
  • Encapsulation: Variables and functions inside a module are private by default. They won’t accidentally interfere with other parts of your code unless you explicitly share them.
  • Maintainability: Smaller, focused files are easier to understand, test, and update than one massive file.

To share code between modules, you need to export it. There are two ways to do this:

Use named exports when you want to share multiple items from a module. Just add the export keyword before your variables or functions:

// formatters.js
export const capitalize = (text) => {
return text.charAt(0).toUpperCase() + text.slice(1).toLowerCase();
};
export const truncate = (text, maxLength) => {
return text.length > maxLength ? text.slice(0, maxLength) + '...' : text;
};
javascript

You can export as many items as you want using named exports.


Use a default export when your module has one main thing to share. Each module can only have one default export:

// validator.js
export default function isValidEmail(email) {
const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailPattern.test(email);
}
javascript

Once you’ve exported code from a module, you can import it into other files. The import syntax matches the export style:

To import named exports, use curly braces {} with the exact names:

// app.js
import { capitalize, truncate } from './formatters.js';
console.log(capitalize('hello world')); // "Hello world"
console.log(truncate('This is a long text', 10)); // "This is a ..."
javascript

For default exports, you can choose any name you like (no curly braces needed):

// app.js
import isValidEmail from './validator.js';
console.log(isValidEmail('user@example.com')); // true
console.log(isValidEmail('invalid-email')); // false
javascript

To import all exports from a module at once, use * as to create a namespace object:

// app.js
import * as formatters from './formatters.js';
console.log(formatters.capitalize('hello')); // "Hello"
console.log(formatters.truncate('Long text here', 5)); // "Long ..."
javascript

This approach is useful when a module exports many items and you want to keep them organized under one name.


To use ES modules in your HTML file, add type="module" to your script tag:

index.html
<script type="module" src="app.js"></script>
html

Now your app.js file can import other modules:

// app.js
import { capitalize } from './formatters.js';
const username = capitalize('alice');
console.log(username); // "Alice"
javascript

When working with modules in the browser, keep these points in mind:

  • Use a web server - Modules must be served over HTTP/HTTPS. Opening HTML files directly (file://) won’t work due to browser security restrictions.
  • Include file extensions - Always write './math.js', not './math'. The .js extension is required in browsers.
  • Modules load asynchronously - They behave like <script defer>, meaning they won’t block page rendering.
  • Use relative paths - When importing local files, start with ./ or ../ to specify the path relative to the current file.