JavaScript Modules: Import and Export Explained

The problem before modules existed
Picture a JavaScript project where every file’s code is loaded into the same global space — no separation, no boundaries. A function named formatDate in one file could silently collide with a different formatDate accidentally defined somewhere else. Finding out which file actually defines a given function meant scrolling through files hoping to spot it, or hoping whoever wrote it left a comment. As a project grows past a handful of files, this stops being a minor annoyance and starts being a genuine source of bugs.
Modules exist to solve exactly this — giving each file its own private scope, and a deliberate, explicit way to share only what it chooses to.
Why Modules Are Needed
The code organization problem
Without modules, every script loaded onto a page effectively shares one giant global space. Two files that happen to declare a variable or function with the same name will silently conflict — whichever loads last simply overwrites the other, often without any error at all.
The dependency problem
Without an explicit system for declaring “this file needs that file,” developers had to carefully manage <script> tag order by hand — loading files in exactly the right sequence, hoping nothing dependent on something else loaded too early.
The maintainability problem
As a codebase grows, understanding “where does this function actually come from” becomes genuinely difficult without an explicit declaration tracing it back to its source file.
What modules fix
A module is simply a single file with its own private scope — nothing inside it is accessible from the outside unless it’s deliberately exported. This single change eliminates naming collisions, makes dependencies explicit and traceable, and turns “where did this come from” into a question with an immediate, provable answer: right there in the import statement.

Exporting Functions or Values
Exporting is how a module explicitly marks something as available to other files.
// mathUtils.js
export function add(a, b) {
return a + b;
}
export function multiply(a, b) {
return a * b;
}
export const PI = 3.14159;Anything not explicitly exported — helper functions, internal variables — stays completely private to that file, invisible to anything importing from it. This is a deliberate design choice: a module’s internal implementation details stay hidden, and only its intended public surface is exposed.

Importing Modules
Importing brings exported values from one module into another, explicitly naming exactly what you want:
// app.js
import { add, multiply, PI } from "./mathUtils.js";
console.log(add(2, 3)); // 5
console.log(multiply(4, 5)); // 20
console.log(PI); // 3.14159The path (./mathUtils.js) tells JavaScript exactly which file to pull these values from — making the dependency between app.js and mathUtils.js explicit and traceable, instead of implicit and easy to lose track of.

Renaming an import
If two modules happen to export something with the same name, you can rename it on import to avoid a collision:
import { add as sum } from "./mathUtils.js";
console.log(sum(2, 3)); // 5
