Skip to main content

Command Palette

Search for a command to run...

JavaScript Modules: Import and Export Explained

Updated
7 min read
JavaScript Modules: Import and Export Explained
M

Software Developer

As JavaScript applications grow, managing code inside a single file becomes increasingly difficult. A small project may start with just a few functions, but over time it can include utility functions, API calls, authentication logic, validation rules, and business logic. Keeping all of this code in one place makes the application difficult to read and maintain.

Life Before Modules

When JavaScript was first introduced, developers usually wrote their entire application in one or two files.

A small project looked manageable.

However, as applications grew, the number of functions also increased.

Imagine a developer building an e-commerce application.

The first version of the project contains only a few functions:

function loginUser() {}

function logoutUser() {}

function addToCart() {}

function calculatePrice() {}

function makePayment() {}

Everything works perfectly.

A few months later, the application starts growing.

New features are added:

  • Product management

  • Shopping cart

  • User authentication

  • Payment gateway

  • Email notifications

  • Order history

  • Inventory management

Instead of creating separate files, the developer keeps adding code to the same file.

The file grows from:

  • 100 lines

  • to 500 lines

  • to 2000 lines

  • and eventually to thousands of lines.

Finding a particular function becomes difficult.

Changing one part of the application may accidentally break another part.

When multiple developers work on the same file, merge conflicts become common.

The project still works, but maintaining it becomes increasingly difficult.

At this point, the developer realizes an important fact:

The problem is not JavaScript.

The problem is how the code is organized.

This realization led to one of the most important features in modern JavaScript:

Modules

Modules allow developers to split applications into smaller files where each file focuses on a single responsibility.

Organizing Code Using Modules

Let us revisit the same e-commerce application.

Instead of keeping everything in one file, the developer decides to organize the code like this:

ecommerce-app

├── auth.js

├── cart.js

├── payment.js

├── products.js

└── app.js

Now each file has a clear purpose.

  • auth.js manages user authentication.

  • cart.js manages cart operations.

  • payment.js handles payment logic.

  • products.js manages product-related functions.

  • app.js connects everything together.

This structure offers several advantages.

A developer working on payments does not need to understand the entire application.

A bug inside cart.js can often be fixed without touching authentication or payment logic.

New features can be added as new modules without increasing the complexity of existing files.

This is the core idea behind modular programming.

Instead of creating one giant file, developers create smaller pieces that work together.

Exporting Functions and Values

After splitting the application into multiple files, a new question appears.

How can one file use code written in another file?

This is where exports become important.

Suppose cart.js contains a function that adds a product to the cart.

export function addToCart(product) {

    console.log(`${product} added to cart`);

}

The export keyword makes this function available outside the file.

Other modules can now use this function.

Modules can export many kinds of values.

For example:

export const TAX_RATE = 0.18;

export const STORE_NAME = "My Store";

A module can also export classes.

export class User {

    constructor(name) {

        this.name = name;

    }

}

The basic idea is simple.

Anything that is exported becomes available to other modules.

Anything that is not exported remains private to that file.

This creates a clear boundary between modules and prevents unnecessary code from being exposed.

Importing Modules

Exporting code is only one part of the story.

The second part is importing it.

Suppose cart.js exports a function:

export function addToCart(product) {

    console.log(`${product} added`);

}

Another file can use this function by importing it.

import { addToCart } from "./cart.js";

addToCart("Laptop");

The curly braces indicate that we are importing a named export.

The syntax may look unusual at first, but it creates a very clear relationship between files.

You can visualize the dependency like this:

cart.js

     │

 exports addToCart()

     │

     ▼

app.js

imports addToCart()

This structure helps developers understand where functions come from and how files depend on each other.

Large applications often contain dozens or hundreds of modules.

Using imports and exports keeps these dependencies organized.

Default Exports

Sometimes a module has one main responsibility.

In such cases, developers often use a default export.

Suppose a file contains a greeting function.

function greet(name) {

    return `Hello ${name}`;

}

export default greet;

Another file can import it like this:

import greet from "./greet.js";

console.log(greet("Alex"));

Notice that curly braces are not required.

A module can have only one default export.

The importing file can even choose a different name.

import sayHello from "./greet.js";

console.log(sayHello("Alex"));

The exported function remains the same.

Only the local name changes.

Default exports are useful when a module exposes one primary feature.

Named Exports

Named exports are useful when a module exposes multiple utilities.

For example:

export function add(a, b) {

    return a + b;

}

export function subtract(a, b) {

    return a - b;

}

export const PI = 3.14;

Another file can import these values:

import {

    add,

    subtract,

    PI

} from "./math.js";

Named exports provide flexibility because developers can import only what they need.

Unused functions remain untouched.

This makes modules easier to understand and maintain.

Default vs Named Exports

A common question among beginners is:

Which export style should I use?

The answer depends on the module.

If a module exposes one main feature, default exports are often a good choice.

If a module contains multiple functions or utilities, named exports are usually preferred.

The differences can be summarized as follows:

Feature Default Export Named Export
Number of exports One Multiple
Curly braces Not required Required
Import name Can be changed Must match
Best use case Main functionality Multiple utilities

There is no universally correct approach.

Many projects use both styles depending on the requirements.

The important goal is to keep modules easy to understand and easy to use.

Benefits of Modular Code

As applications continue to grow, the advantages of modules become even more obvious.

Better Organization

Modules divide applications into smaller files.

Each file has a clear responsibility, making the project easier to navigate.

Reusability

Functions written in one module can be imported and reused in different parts of the application.

This reduces duplication and promotes consistency.

Easier Maintenance

Smaller files are easier to read and modify.

Developers can update one module without affecting unrelated parts of the application.

Better Team Collaboration

In large teams, different developers can work on different modules simultaneously.

One developer can work on authentication while another focuses on payments.

This reduces merge conflicts and improves productivity.

Improved Scalability

New features can be added as separate modules.

The application grows in a structured way instead of becoming one enormous file.

Conclusion

JavaScript Modules were introduced to solve a very practical problem:

Managing growing codebases.

As applications become larger, keeping all code inside a few files becomes difficult to maintain. Modules encourage developers to divide applications into smaller, focused files that communicate using imports and exports.

Exporting allows a module to expose functionality.

Importing allows other modules to use that functionality.

Default exports are useful when a file exposes one primary feature, while named exports are better suited for modules containing multiple utilities.

Modern JavaScript development relies heavily on modules because they improve organization, reusability, maintainability, and scalability.

Understanding modules is therefore not just about learning import and export.

It is about learning how to structure applications in a way that remains clean and maintainable as projects continue to grow.

#javascript #modules #import #export #esmodules #webdevelopment #frontend #backend #hashnode