JavaScript Modules: import and export explained

One file. Thousand lines.
You need a function from the bottom. You scroll. And scroll. And scroll.
This is chaos.
Let me show you how modules fix this.
Why Modules Are Needed
Remember the old days?
<script src="app.js"></script>
<script src="utils.js"></script>
<script src="api.js"></script>
All variables were global.
One file overwrites another's variable. No warning. Just bugs.
Problems:
| Problem | What happens |
|---|---|
| Global namespace pollution | Everything is everywhere |
| No encapsulation | Can't hide internal code |
| Hard to maintain | Change one thing, break another |
| Impossible to reuse | Copy-paste code across files |
Modules solve all of this.
What is a Module?
A module is a file. That's it.
One file = one module.
Code inside is private by default. Nothing leaks out unless you explicitly export it.
Other files can import only what they need.
Think of it as:
"Export what you want to share. Import what you need to use."
Exporting Functions or Values
Named Export (Multiple per file)
Export as you create:
// utils.js
export const add = (a, b) => a + b;
export const subtract = (a, b) => a - b;
export const PI = 3.14159;
Or export at the bottom:
// utils.js
const add = (a, b) => a + b;
const subtract = (a, b) => a - b;
export { add, subtract };
Default Export (One per file)
// math.js
const calculate = (a, b) => a * b;
export default calculate;
Or directly:
export default function multiply(a, b) {
return a * b;
}
Rule: One file can have many named exports, but only one default export.
Importing Modules
Importing Named Exports
// app.js
import { add, subtract } from './utils.js';
console.log(add(5, 3)); // 8
console.log(subtract(5, 3)); // 2
Rename while importing:
import { add as sum, subtract as difference } from './utils.js';
Import everything as an object:
import * as Utils from './utils.js';
console.log(Utils.add(5, 3));
console.log(Utils.subtract(5, 3));
Importing Default Export
// app.js
import calculate from './math.js';
console.log(calculate(4, 5)); // 20
Note: Default import can have any name. No curly braces.
Mixed Import (Default + Named)
// file has both export default and named exports
import calculate, { add, subtract } from './math.js';
Default vs Named Exports – Quick Comparison
| Feature | Named Export | Default Export |
|---|---|---|
| Per file | Multiple | Only one |
| Import syntax | { name } |
No curly braces |
| Rename on import | as keyword |
Any name works |
| Best for | Utilities, helpers | Main thing of the file |
When to use what?
Use named exports for multiple related functions/values.
Use default export when the file has one primary thing (a class, main function).
The File Dependency Flow
Imagine this structure:
project/
├── main.js
├── math.js
└── logger.js
math.js exports functions. logger.js exports a default logger. main.js imports from both.
// math.js
export const add = (a, b) => a + b;
export const multiply = (a, b) => a * b;
// logger.js
export default function log(msg) {
console.log(`[LOG]: ${msg}`);
}
// main.js
import { add, multiply } from './math.js';
import log from './logger.js';
const result = add(2, 3);
log(`Result is ${result}`); // [LOG]: Result is 5
Flow: main.js → math.js and logger.js. No global pollution. Clean.
Benefits of Modular Code
| Benefit | Explanation |
|---|---|
| Encapsulation | Internal code stays private |
| Reusability | Import the same module anywhere |
| Maintainability | Change one file, others work if exports unchanged |
| No namespace pollution | No accidental variable collisions |
| Clear dependencies | You know exactly what each file needs |
| Easier testing | Test each module in isolation |
The Correct Import Order
Always follow this order:
Built-in Node.js modules (if using Node)
Third-party packages (from npm)
Your own modules (local files)
Why? Clarity and precedence. Built-in first, then external, then internal.
// ✅ Correct order
import fs from 'fs'; // Built-in
import express from 'express'; // Third-party
import { add } from './math.js'; // Local
import log from './logger.js'; // Local
Wrong order:
// ❌ Don't mix randomly
import { add } from './math.js';
import fs from 'fs';
import lodash from 'lodash';
Keep it clean. Readability matters.
How to Use Modules in Browser
Two things needed:
- Add
type="module"to script tag:
<script type="module" src="main.js"></script>
- Use
.jsor.mjsextension (both work).
Important: Modules are deferred by default. They wait for HTML to load.
Common Mistakes
Mistake 1: Forgetting {} for named imports
// ❌ Wrong
import add from './utils.js'; // but add is named export
// ✅ Correct
import { add } from './utils.js';
Mistake 2: Trying default import with wrong name
// ❌ Wrong for default export
import { calculate } from './math.js'; // calculate is default
// ✅ Correct
import calculate from './math.js';
Mistake 3: Missing file extension
// ❌ May not work in browsers
import { add } from './utils';
// ✅ Always include .js
import { add } from './utils.js';
Mistake 4: Mixing default and named incorrectly
// ❌ Wrong order
import { add }, calculate from './math.js';
// ✅ Correct: default first, then named
import calculate, { add } from './math.js';
Mistake 5: Wrong import order
// ❌ Third-party before built-in
import express from 'express';
import fs from 'fs';
import cors from 'cors';
// ✅ Built-in first
import fs from 'fs';
import express from 'express';
import cors from 'cors';
Final Thought
Modules keep your code organized, private, and reusable.
Export what's needed. Import what's used.
One file = one responsibility.
And remember: built-in → third-party → local. Always.




