---
title: Using modules in JavaScript
published: "2022-09-29"
updated: "2025-03-07"
publisher: Honeybadger
author: Adebayo Adams
category: JavaScript articles
tags:
  - JavaScript
description: Do you want to write cleaner JavaScript? Jump into this article to learn how modules in JavaScript can make your code better.
url: "https://www.honeybadger.io/blog/javascript-modules-encapsulation/"
---

Modules are one of the most commonly used JavaScript features because [most JavaScript frameworks](https://www.honeybadger.io/blog/what-nextjs-has-to-offer-react-devs/) and libraries leverage the module feature for organization and componentization. Modules in JavaScript are probably underused—some developers even think that the import and export keywords are ReactJS features.

In this article, we'll explain how to encapsulate code using the module system to make your projects cleaner. To start, let's take a look at what encapsulation is in the next section.

![Modules in JavaScript with encapsulation](https://www-files.honeybadger.io/posts/javascript-modules-encapsulation/encapsulation.png)

## Encapsulation in JavaScript

In programming, encapsulation refers to bundling related code in a single source. The code can include associated functions and variables inside files or related files inside a folder.

Encapsulation is used to restrict direct access to data and implementations of the bundled and related code from the code that uses them. Thus, the implementation of the functionalities is hidden, can't be manipulated by other parts of the code, and will only change when you want to change it. For example, in a blog application, when you bundle all the post properties and methods in a single unit, you only need to give the code that needs to interact with it: the name of the functions and the values they need to work.

Encapsulation is necessary because it makes your code cleaner, maintainable, and easier to understand, reuse, and test. Limiting access to information via encapsulation is a strong programming norm, and helps to reduce the size of a module's public interface. This makes units of code easier to interact with and more predictable.

Next, let's dig into JavaScript modules.

## Modules in JavaScript

A module is an independent, self-contained, and detachable unit of a program. JavaScript allows you to structure large programs and codebases by creating JS modules of code that hold related functions and properties that can be exported into multiple other JS files that need these properties and functions.

Code organization is the major reason a framework is a go-to option for most developers when building medium to large applications. Fortunately, frameworks are not the only way to use JavaScript modules. I'll walk you through how to structure your code with JavaScript modules. First, let's look at the syntax of JavaScript modules.

### JavaScript exports

Using modules makes functionalities available for other modules; the `export` keyword makes this possible. You can make a function accessible by other modules:

```js
export function verifyUser(email, password) { // do all necessary checks return "Successfully verified user!" }
```

> Note: JS Files that import or export code are known as modules.

The above function is ready to be used in other modules that need the `verifyUser` function. This is called a named export.

### Exporting multiple properties

Using the `export` keyword, you can export anything from variables to even classes. To export multiple properties from a module, you need to prefix the declaration with the `export` keyword:

```js
export const userName = "Lee"; export const userAge = 30; export const user = { name: "Lee", age: 30 };
```

The code above exports all the declarations in the module. This example exports everything, but you don't need to export everything in a module. You can have declarations that are only available for use inside the module and choose what gets exported, like in this example:

```js
const apiKey = "1234"; export function getApiKey() { return apiKey; }
```

> Note: A declaration is a function, class, variable, or anything declared inside a module.

The code above exports only the `getApiKey` function, which returns the `apiKey` variable declared above the function. While the `apiKey` variable is not accessible outside this module, the exported `getApiKey` function makes its value readable.

An even cleaner way to export multiple properties is using the curly brackets notation. Let's say you have several functions that you'd like to export, like in this example:

```js
// user sign in function userSignIn() { console.log("User signed in"); } // user sign out function userSignOut() { console.log("User signed out"); } // delete task function deleteTask(id) { console.log(`Task ${id} deleted`); } //add task function addTask(task) { console.log(`Task ${task.id} added`); } //edit task function editTask(id, changes) { console.log(`Task ${id} edited`); } //complete task function completeTask(id) { console.log(`Task ${id} completed`); }
```

You can export all the functions in the block of code above with a single `export` statement:

```js
export { userSignIn, userSignOut, deleteTask, addTask, editTask, completeTask };
```

The above block of code exports all the declarations inside the curly braces and is available for imports in other modules, so now the complete JavaScript module looks like this:

```js
// user sign in function userSignIn() { console.log("User signed in"); } // user sign out function userSignOut() { console.log("User signed out"); } // delete task function deleteTask(id) { console.log(`Task ${id} deleted`); } //add task function addTask(task) { console.log(`Task ${task.id} added`); } //edit task function editTask(id, changes) { console.log(`Task ${id} edited`); } //complete task function completeTask(id) { console.log(`Task ${id} completed`); } export { userSignIn, userSignOut, deleteTask, addTask, editTask, completeTask };
```

> Note: The `export {...}` block of code is typically placed at the bottom of the module for readability, but you can place it anywhere inside the module.

### Default exports

Sometimes, you might have a function over 100 lines of code and want to place it alone in a single file. To make importing it into other modules easier, you can make it a default export:

```js
// google sign in export default function googleSignIn() { // 100 lines of checking and getting details console.log("User signed in with Google"); }
```

The above function is being exported as the default from the module. This changes nothing for the export but makes importing a bit easier. I will show you how to use the `import` keyword in the next section.

> Note: A module can have only one `default` export.

### Using the import keyword

In the previous section, you learned about using the export keyword to make properties of a module available for other modules. In this section, I'll teach you how to use the import keyword to get code from other modules.

### Importing

To use code from other modules, you can import them using the `import` keyword:

```js
import { userSignIn, userSignOut } from "./filePath.js";
```

> Note: The `"./filePath"` is a relative path to the directory route.

The code above imports the userSignIn and userSignOut functions from the declared module. You can import one or more declarations; the only requirement is to ensure the property is defined in the module from which you are importing.

### Importing `default` exports

In the "Default Exports" section above, you learned how to export functions as default from modules. Now let's look into how to import exported declarations as default.

You can import a default export using the following:

```js
import googleSignIn from "./filePath.js";
```

The above code imports the `googleSignIn` function, which was exported as default in the previous section. Because a module can have only one default export, you can omit the name of the function declaration, and the above code will still work; this means you can declare the function without a name:

```js
// google sign in export default function () { // 100 lines of checking and getting details console.log("User signed in with Google"); }
```

The above code will work because it is a default export.

The only difference between importing a default and a named export is the curly braces:

```js
// default export, no braces import googleSignIn from  "./filePath.js"; // named export, must use braces import { userSignIn, userSignOut } from "./filePath.js";
```

### Namespace import

Sometimes, you have a module containing many different utility functions and want to use a single name to access them; this name is called a `namespace`.

For example, let's say you have defined all user-related functions in a module:

```js
function getUserName() { return userName; } function getUserAge() { return userAge; } function getUser() { return user; } function getApiKey() { return apiKey; } function userSignIn() { console.log("User signed in"); } function userSignOut() { console.log("User signed out"); } export { getUserName, getUserAge, getUser, getApiKey, userSignIn, userSignOut, };
```

Then, you import all of these into the module that needs to use them:

```js
import * as userFuncs from './filePath.js';
```

The above code uses a special character `*` to import all the declarations in the module on top of the `userFuncs`. You can access the `getUserName` in the module:

```js
import * as userFuncs from './filePath.js'; // use getUserName function userFuncs.getUserName();
```

### Renaming JavaScript declarations

To help developers avoid naming collisions, JavaScript modules use the `as` keyword to rename declarations.

### Renaming exports

Sometimes, you might have a declaration that has a name collision with another declaration. Let's say you have a function named `login` and you're using another library that has a function named `login`. You can export your login function as myLogin by renaming it:

```js
function login(email, password) { // check if your email and password are valid return "User logged in"; } // export as myLogin export { login as myLogin };
```

The code above declares a login function but exports it as myLogin. You can import the function as myLogin:

```js
import { myLogin } from "./filePath.js";
```

The above function imports the `myLogin` function. Next, let's look into how to rename imports.

### Renaming imports

When working on a large project, you will import from multiple modules, making it easier to mix up declaration names. For example, you might be working with two different libraries, one for Twitter authentication and the other for Google authentication, and both have their own `login` function. Just like you might want to rename an export, you might want to rename an import. To avoid naming collisions, in the case of this example, you can import them with different names:

```js
// import twitter login import login as twitterLogin from 'twitter-auth'; // import google login import login as googleLogin from 'google-auth';
```

The above code imports the login function of two different libraries with specific names. This way, it's easier to avoid bugs and helps other developers understand your code.

Next, I'll show you how to re-export a declaration.

### Re-exporting

Although it’s not commonly used, JavaScript modules allow you to re-export a module you previously imported:

```js
// import the login function import { login  } from './filePath.js'; // re-export the login function export { login };
```

The above code imports the `login` function and then re-exports it.

Now that you know how to use import and export, I'll show you how to structure applications using modules.

## Structuring JavaScript code with modules

In the previous sections, you learned how to use the import and export keywords to make code available in different and multiple modules. In this section, we'll dig into the practical benefits of using modules and how they can help you structure your code and applications.

### Modules help with reusability

Whether you're a beginner, intermediate, or advanced developer, you've probably seen the term "DRY" or "Don't Repeat Yourself" on the internet.

What this means is that most times, you can reuse functions multiple times in different parts of the code. As you have learned in the previous sections, modules make this easier because all you need to do is write the code, export it, and then use it in other modules that need the particular function.

A few of the benefits of this approach are as follows:

- It saves time
- It increases the maintainability and portability of your code
- It increases the productivity of developers working on your codebase
- It reduces redundancy across your project

These are just a few benefits of reusability that using modules helps you achieve.

### Modules help with composability

Composability allows you to break functionality into pieces and bring them together to form the whole function, as well as allow you to reuse the parts of the function in other parts of the application.

An example of this is when creating an `addComment` function, you might want to make some checks or mutations inside the function:

- Is this user allowed to comment?
- Remove prohibited characters like `<h1></h1>` from input.
- Is this input length greater than the allowed characters?
- Add the supplied input to the database.

Then, you can create these four different functions, for example:

```js
// check if user if allowed to comment export default function canComment(user) { // make checks here return user.signedIn; } // check if input contains html tags export function containsHTML(input) { return /<[a-z][\s\S]*>/i.test(input); } // check if input is not longer than maxLength export function isTooLong(input, maxLength) { return input.length > maxLength; } // add input to the database export function addToDatabase(input) { console.log(`${input} added to database`); }
```

The above functions can now be combined to create the `addComment` function:

```js
function addComment(user, comment) { if (canComment(user) && !containsHTML(comment) && !isTooLong(comment)) { addToDatabase(comment); } }
```

Each function that makes up the `addComment` function can also be used independently in other parts of the program.

The benefits of composability from modules include the following:

- It makes your code cleaner.
- It makes it easier to reuse existing code.
- It makes it easier to separate concerns.
- It makes code easy to understand.

### Modules help you isolate code

Understanding the whole project can be difficult for new team members working on a large project.

Because modules allow you to build the application by composing small, focused functions, each of these functions can be created, repaired, and thought of in isolation.

Using the example in the previous section, to change the implementation to check whether the user can comment, you only need to modify the `canComment` function. The rest can remain unchanged.

Isolation, similar to encapsulation, makes it easier to understand, modify, and test your code.

### Modules make your code more readable

Using modules in your code makes it easier to read. This is especially necessary when working on large applications, and it's almost impossible to explain to each developer on the team what you're trying to do with a function.

For example, without going into each file to see the implementation, a developer almost automatically knows what the following function does:

```js
function addComment(user, comment) { if (canComment(user) && !containsHTML(comment) && !isTooLong(comment)) { addToDatabase(comment); } }
```

The code above can be read as, "If the user can comment, the comment does not contain HTML, and the comment is not too long, add the comment to the database." The underlying implementation of each function doesn't need to be loaded into working memory to have a good understanding of the intention of this `addComment` function. This makes it easier for new team members to start contributing to the project, which saves time.

### Modules organization easier

When using JavaScript modules, organization occurs almost automatically because each part of the code is isolated.

For example, you might have all the functions used to check the type of declarations inside a `typeUtils.js`:

```js
// check if input is a string export function isString(input) { return typeof input === "string"; } // check if input is a number export function isNumber(input) { return typeof input === "number"; } // check if input is an array export function isArray(input) { return Array.isArray(input); } // check if input is an object export function isObject(input) { return typeof input === "object"; } // check if input is a function export function isFunction(input) { return typeof input === "function"; } // check if input is a boolean export function isBoolean(input) { return typeof input === "boolean"; } // check if input is null export function isNull(input) { return input === null; }
```

Without giving it much thought, the above code is organized, as they are all related and independent of one another.

## Using modules in your own applications

I hope you enjoyed this tutorial! Hopefully, you better understand how using the module system in JavaScript can improve your code. In this article, you learned what encapsulation is, what modules are and how they function, as well as explored how export and import keywords work and how to rename declarations. Finally, you learned how modules can help structure your code.

While using modules _unlocks_ a lot of codebase improvements, it's still important that you apply a careful eye to the design of your modules, using good [object oriented design](https://www.honeybadger.io/blog/javascript-oop/) to fully take advantage of all they have to offer.

---

## Try Honeybadger for FREE

Intelligent logging, error tracking, and Just Enough APM™ in one dev-friendly platform. Find and fix problems before users notice.

[Start free trial](https://app.honeybadger.io/users/sign_up)

[See plans and pricing](https://www.honeybadger.io/plans/)
