JavaScript modules allow developers to split a large JavaScript program into smaller, reusable files. Instead of writing all the code in one file, you can organize functions, variables, classes, and other code into separate files and share them when needed.
JavaScript provides the export and import keywords to make this possible. The export keyword makes code available to other modules, while the import keyword allows another module to use that exported code.
In this tutorial, you will learn how JavaScript modules work, how to export and import functions and variables, the difference between named exports and default exports, and how to use modules in a real project.
What Are JavaScript Modules?
A JavaScript module is a file that contains code designed to be used independently or shared with other JavaScript files.
For example, imagine you are building a calculator application. You could write addition, subtraction, multiplication, and division functions in separate files instead of keeping everything in one large file.
A project might have this structure:
calculator/
├── index.html
├── main.js
└── math.js
The math.js file contains mathematical functions, while main.js imports and uses those functions.
Modules make code easier to maintain, test, organize, and reuse.
Why Are JavaScript Modules Important?
JavaScript modules offer several benefits:
- Code organization: Divide a large application into smaller files.
- Code reusability: Use the same function or class in multiple files.
- Maintainability: Update one module without rewriting the entire application.
- Avoiding naming conflicts: Each module has its own scope.
- Team collaboration: Developers can work on separate modules.
- Better project structure: Keep related functionality together.
Before native JavaScript modules became widely available in browsers, developers often used approaches such as separate script files, immediately invoked function expressions (IIFEs), or module systems provided by tools. Modern JavaScript supports modules through import and export.
What Is the export Keyword in JavaScript?
The export keyword allows you to make variables, functions, classes, and other declarations available to other JavaScript modules.
For example, create a file named math.js:
export function add(a, b) {
return a + b;
}
The add() function is now available for other modules to import.
Without an export, another module cannot directly import that function from this file.
There are two main types of exports:
- Named exports
- Default exports
Named Exports in JavaScript
Named exports allow you to export multiple variables, functions, or classes from a single module. Each exported item has a specific name.
Export a Function
Create a file named math.js:
export function add(a, b) {
return a + b;
}
export function subtract(a, b) {
return a - b;
}
Both add() and subtract() are named exports.
You can import either function or both functions into another file.
Export Variables
You can also export variables from a module.
export const siteName = "Web4Learners";
export let visitorCount = 100;
Another module can import these variables and read their values.
Remember that importing a variable does not create an independent copy that you can freely reassign. Module imports are read-only live bindings to the exported value.
Export a Class
JavaScript classes can also be exported.
export class Student {
constructor(name) {
this.name = name;
}
introduce() {
return `My name is ${this.name}`;
}
}
Another module can import the Student class and create objects from it.
You can learn more about JavaScript Classes to understand how classes and objects work.
Export After Declaring
You do not have to write export before every declaration. You can declare your code first and export it later.
function multiply(a, b) {
return a * b;
}
function divide(a, b) {
return a / b;
}
export { multiply, divide };
The curly braces contain the names of the declarations you want to export.
This approach is useful when you want to keep your declarations together and define your module’s public interface at the end of the file.
What Is the import Keyword in JavaScript?
The import keyword allows one JavaScript module to use declarations exported by another module.
For example, suppose math.js contains this function:
export function add(a, b) {
return a + b;
}
You can import it into main.js:
import { add } from "./math.js";
console.log(add(10, 20));
Output:
30
Here is what the code means:
importtells JavaScript to load an exported declaration.{ add }identifies the named export."./math.js"specifies the relative path to the module.add(10, 20)calls the imported function.
The ./ indicates that math.js is located relative to the current file.
For browser-based JavaScript, the HTML page must load main.js as a module.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>JavaScript Modules</title>
</head>
<body>
<h1>JavaScript Modules</h1>
<script type="module" src="./main.js"></script>
</body>
</html>
The type="module" attribute tells the browser to treat main.js as an ES module.
For browser testing, run the files through a local development server rather than opening the HTML file directly using a file:// URL. Module loading and imports generally require an HTTP or HTTPS origin.
Import Multiple Named Exports
You can import multiple named exports from the same file.
Suppose math.js contains:
export function add(a, b) {
return a + b;
}
export function subtract(a, b) {
return a - b;
}
export function multiply(a, b) {
return a * b;
}
In main.js, import the functions you need:
import { add, subtract, multiply } from "./math.js";
console.log(add(5, 3));
console.log(subtract(5, 3));
console.log(multiply(5, 3));
Output:
8
2
15
You can import only the declarations your module needs. You do not have to import every named export from a file.
Rename Imports Using as
Sometimes, an imported name may conflict with another variable or may not clearly describe its purpose in the current file.
JavaScript lets you rename an imported declaration using the as keyword.
For example, math.js contains:
export function add(a, b) {
return a + b;
}
In main.js:
import { add as calculateSum } from "./math.js";
console.log(calculateSum(10, 15));
Output:
25
The exported function is still named add, but it is available locally as calculateSum in main.js.
You can also rename exports using as:
function greet() {
return "Hello from Web4Learners!";
}
export { greet as sayHello };
Other modules can import the function using its exported name:
import { sayHello } from "./greetings.js";
console.log(sayHello());
Output:
Hello from Web4Learners!
What Is a Default Export?
A default export allows a module to provide one primary value or declaration for importing.
Unlike named exports, a module can have only one default export.
For example, create greetings.js:
export default function greet() {
return "Welcome to Web4Learners!";
}
You can import the default export into main.js:
import greet from "./greetings.js";
console.log(greet());
Output:
Welcome to Web4Learners!
Notice that the import does not use curly braces around greet.
You can choose a different local name when importing a default export:
import welcomeMessage from "./greetings.js";
console.log(welcomeMessage());
This works because the import name for a default export is chosen by the importing module.
Default Export a Class
You can also use a default export for a class.
export default class Product {
constructor(name, price) {
this.name = name;
this.price = price;
}
getDetails() {
return `${this.name}: ₹${this.price}`;
}
}
Import the class into another file:
import Product from "./Product.js";
const product = new Product("Keyboard", 1200);
console.log(product.getDetails());
Output:
Keyboard: ₹1200
The class is exported as the module’s default value, so it can be imported without curly braces.
Named Exports vs Default Exports
Named exports and default exports both make code available to other modules, but they work differently.
| Feature | Named Export | Default Export |
|---|---|---|
| Number per module | Multiple allowed | One allowed |
| Import syntax | Usually uses curly braces | Does not use curly braces |
| Import name | Must match the exported name unless renamed | Can use a chosen local name |
| Example export | export const age = 25; | export default 25; |
| Example import | import { age } from "./data.js"; | import age from "./data.js"; |
Use named exports when a module provides several related functions or values. Use a default export when the module has one main declaration that represents its primary purpose.
A module can contain both named exports and one default export.
Import All Named Exports Using *
If you want to access multiple named exports through one object-like namespace, you can use * as.
Suppose math.js contains:
export const pi = 3.14159;
export function square(number) {
return number * number;
}
export function cube(number) {
return number * number * number;
}
Import all its named exports into a namespace:
import * as MathTools from "./math.js";
console.log(MathTools.pi);
console.log(MathTools.square(4));
console.log(MathTools.cube(3));
Output:
3.14159
16
27
The name MathTools represents a module namespace. You can access its exported properties using dot notation.
For a refresher, see JavaScript Dot Notation.
This syntax imports all named exports into the namespace. It does not include the default export as a named property called default in the same way that named exports are exposed, so be careful when working with default exports.
Import and Rename Multiple Exports
You can combine named imports with aliases when importing several declarations.
Suppose user.js contains:
export const userName = "Karim";
export function getWelcomeMessage() {
return `Welcome, ${userName}!`;
}
Import the declarations with different local names:
import {
userName as name,
getWelcomeMessage as welcome
} from "./user.js";
console.log(name);
console.log(welcome());
Output:
Karim
Welcome, Karim!
This is especially helpful when combining exports from multiple modules that contain similar names.
Re-Export Declarations From Another Module
A module can also export declarations that it imports from another file. This is called re-exporting.
For example, suppose math.js exports two functions:
export function add(a, b) {
return a + b;
}
export function subtract(a, b) {
return a - b;
}
You can create another file named index.js:
export { add, subtract } from "./math.js";
Now another file can import the functions from index.js:
import { add, subtract } from "./index.js";
console.log(add(7, 3));
console.log(subtract(7, 3));
Output:
10
4
Re-exporting is useful when building larger applications or libraries. You can group exports from several modules behind one entry point, making imports simpler for the rest of the project.
Practical Example: Creating a Student Module
Let’s create a small example that demonstrates how modules work together.
Project structure:
student-app/
├── index.html
├── main.js
└── student.js
Create the student.js File
This file exports a function that creates a student profile.
export function createStudent(name, course) {
return {
name,
course
};
}
The function returns an object containing the student’s name and course. If you need a refresher on objects, read JavaScript Objects.
Create the main.js File
Import the function and use it to create a student profile.
import { createStudent } from "./student.js";
const student = createStudent("Karim", "JavaScript");
console.log(student.name);
console.log(student.course);
console.log(student);
Output:
Karim
JavaScript
{ name: "Karim", course: "JavaScript" }
The exact formatting of the object in the console may differ between browsers.
Create the index.html File
Load the JavaScript entry point as a module.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Student Module Example</title>
</head>
<body>
<h1>Student Profile</h1>
<p>Open the browser console to see the result.</p>
<script type="module" src="./main.js"></script>
</body>
</html>
Run the project through a local server and open the browser console. You will see the student details printed there.
This example shows how to keep the student-related functionality in one file and use it in another.
Important Rules for JavaScript Modules
Keep these rules in mind when working with import and export.
- Use
type="module"when loading a browser entry-point script as a module. - Use the correct file path when importing a local module.
- Named imports must match the exported name unless you use an alias.
- Default imports do not require curly braces.
- A module can have multiple named exports but only one default export.
- Static
importandexportdeclarations must appear at the top level of a module, not inside functions, loops, or conditional blocks. - Module imports are read-only bindings to the exported declarations.
- Browser modules follow module loading rules, including origin and CORS restrictions.
- ES modules use strict mode automatically.
- Top-level declarations in a module do not automatically become properties of the global
windowobject in a browser.
JavaScript Modules in Node.js
JavaScript modules are also supported in Node.js. However, the project must be configured to use ES modules.
One common approach is to add this to package.json:
{
"type": "module"
}
Then you can use import and export in .js files:
// math.js
export function add(a, b) {
return a + b;
}
// main.js
import { add } from "./math.js";
console.log(add(2, 8));
Run the program with:
node main.js
Output:
10
Node.js also supports CommonJS modules, which use require() and module.exports. CommonJS and ES modules are different module systems, so their syntax and interoperability rules are not identical.
Common Mistakes When Using Import and Export
Forgetting Curly Braces for Named Imports
Incorrect:
import add from "./math.js";
If math.js exports add as a named export, the import above is incorrect.
Correct:
import { add } from "./math.js";
Using Curly Braces for a Default Import
Incorrect:
import { greet } from "./greetings.js";
This is incorrect if greetings.js exports only a default function and does not have a named export called greet.
Correct:
import greet from "./greetings.js";
Using the Wrong File Path
Incorrect:
import { add } from "math.js";
For a relative file in the same directory, use:
import { add } from "./math.js";
The ./ prefix indicates a relative path. Omitting it can cause the runtime or bundler to interpret the specifier differently.
Forgetting type="module"
If you use import or export in a browser script that is loaded as a classic script, the browser may report a syntax error.
Use:
<script type="module" src="./main.js"></script>
Trying to Export the Same Default More Than Once
A module cannot contain multiple default exports. If you need to export several functions, use named exports for those functions and optionally keep one default export for the main declaration.
Frequently Asked Questions
What is the difference between import and export in JavaScript?
The export keyword makes declarations available to other modules. The import keyword brings exported declarations into another module so they can be used there.
Can a JavaScript file have multiple exports?
Yes. A JavaScript module can have multiple named exports. It can also have one default export alongside its named exports.
Can I import a function from another JavaScript file?
Yes. Export the function from the original file, then import it using the correct name and file path.
Do I need a server to use JavaScript modules?
For browser-based projects, use a local development server or a hosted HTTP/HTTPS environment. Opening an HTML file directly through file:// often causes module-loading restrictions.
What is the difference between named and default imports?
Named imports identify exports by name and normally use curly braces. Default imports refer to the module’s default export and do not use curly braces.
Can I rename an imported function?
Yes. Use as to assign a different local name to a named import.
import { add as sum } from "./math.js";
You can then call sum() in the current module.
Are JavaScript modules supported in modern browsers?
Yes. Modern browsers support native ES modules. You can load them with <script type="module"> and use import and export.
Conclusion
JavaScript modules help you organize code into separate, reusable files. The export keyword makes functions, variables, and classes available to other modules, while import allows you to use those declarations elsewhere.
Understanding named exports, default exports, aliases, namespace imports, and module paths will help you build cleaner and more maintainable JavaScript applications. These concepts are essential when working with modern JavaScript projects, including applications built with tools such as Vite and frameworks such as React.