Skip to main content

Exporting and Importing Modules

Introduction​

As your JavaScript projects grow, you'll quickly realize that putting all code in one file becomes a nightmare! Imagine a 10,000-line fileβ€”impossible to navigate and maintain! 😡

This is where modules come to the rescue. Modules let you split your code into separate files that can share functionality with each other.

The Problem: Everything in One File πŸ˜“β€‹

// app.js (10,000 lines of chaos!)

function calculateTax(price) { /* ... */ }
function validateEmail(email) { /* ... */ }
function formatDate(date) { /* ... */ }
function connectDatabase() { /* ... */ }
// ... 9,950 more lines ...

Problems:

  • Hard to find specific code
  • Multiple developers can't work simultaneously
  • Can't reuse code in other projects
  • Testing is difficult

The Solution: Modules! βœ¨β€‹

// utils/tax.js
export function calculateTax(price) { /* ... */ }

// utils/validation.js
export function validateEmail(email) { /* ... */ }

// utils/formatting.js
export function formatDate(date) { /* ... */ }

// database/connection.js
export function connectDatabase() { /* ... */ }

// app.js (clean and organized!)
import { calculateTax } from './utils/tax.js';
import { validateEmail } from './utils/validation.js';
import { formatDate } from './utils/formatting.js';
import { connectDatabase } from './database/connection.js';

Benefits:

  • βœ… Organized - Each file has a clear purpose
  • βœ… Reusable - Import code into any project
  • βœ… Maintainable - Easy to find and fix bugs
  • βœ… Collaborative - Multiple developers can work on different files
  • βœ… Testable - Test each module independently

Two Module Systems πŸ”„β€‹

JavaScript has two main module systems:

  1. ES6 Modules (Modern, recommended)

    • Uses import and export
    • Browser and Node.js (newer versions)
    • The standard for modern JavaScript
  2. CommonJS (Older, Node.js)

    • Uses require() and module.exports
    • Traditional Node.js modules
    • Still widely used in Node.js projects
Which Should You Learn?

Start with ES6 Modules (import/export) - they're the modern standard and work everywhere (browsers + Node.js). Learn CommonJS later if you work with older Node.js projects.

Let's dive into both systems!

ES6 Modules (Modern Way) πŸš€β€‹

ES6 introduced a clean, modern syntax for working with modules. This is the recommended approach for new projects!

The Two Types of Exports​

Think of exports like different ways to share items from a toolbox:

  1. Default Export - The "main tool" in the box (one per file)
  2. Named Exports - Multiple specific tools you can pick from
Toolbox (module.js)
β”œβ”€β”€ πŸ”§ Main Tool (default export) ← Only one
└── πŸ”¨πŸͺ›βœ‚️ Other Tools (named exports) ← Many

Quick Decision Guide:

// One main thing to export? Use default export
export default Calculator;

// Multiple things to export? Use named exports
export { add, subtract, multiply, divide };

// Can also mix both!
export default Calculator;
export { PI, E };

Default Export (One Main Export) πŸ“¦β€‹

Use default export when a file has one main thing to share.

When to use:

  • A file focused on one component/class/function
  • The main feature of the module
  • Want flexibility in import naming
calculator.js (exporting)
// Option 1: Export at declaration
export default function calculate(a, b, operation) {
if (operation === 'add') return a + b;
if (operation === 'subtract') return a - b;
return 0;
}

// Option 2: Export at the end
function calculate(a, b, operation) {
if (operation === 'add') return a + b;
if (operation === 'subtract') return a - b;
return 0;
}
export default calculate;
app.js (importing)
// Can name it whatever you want!
import calculator from "./calculator.js";
// OR
import calc from "./calculator.js";
// OR
import anything from "./calculator.js";

// All work the same way
console.log(calculator(5, 3, 'add')); // 8
Default Export Flexibility

With default exports, you can name the import whatever you want because there's only one thing being exported:

// utils.js
export default function greet() {
return "Hello!";
}

// app.js - ALL of these work!
import greet from "./utils.js"; // βœ…
import sayHello from "./utils.js"; // βœ…
import greeting from "./utils.js"; // βœ…
import xyz from "./utils.js"; // βœ… (works but confusing!)

Best practice: Use meaningful names that describe what you're importing!

Real-World Examples​

Example 1: Exporting a Class

User.js
export default class User {
constructor(name, email) {
this.name = name;
this.email = email;
}

greet() {
return `Hello, I'm ${this.name}`;
}
}
app.js
import User from "./User.js";

const user = new User("Alice", "alice@example.com");
console.log(user.greet()); // "Hello, I'm Alice"

Example 2: Exporting Configuration

config.js
const config = {
apiUrl: "https://api.example.com",
timeout: 5000,
retries: 3
};

export default config;
app.js
import config from "./config.js";

console.log(config.apiUrl); // "https://api.example.com"

Named Exports (Multiple Exports) πŸ“šβ€‹

Use named exports when you want to share multiple things from one file.

When to use:

  • A file with multiple utility functions
  • Sharing constants and functions together
  • Want precise control over what gets imported
mathUtils.js (exporting)
// Option 1: Export individually
export const PI = 3.14159;
export const E = 2.71828;

export function add(a, b) {
return a + b;
}

export function subtract(a, b) {
return a - b;
}

// Option 2: Export all at once (cleaner!)
const PI = 3.14159;
const E = 2.71828;

function add(a, b) {
return a + b;
}

function subtract(a, b) {
return a - b;
}

export { PI, E, add, subtract };
app.js (importing)
// Import specific things (use exact names!)
import { PI, add, subtract } from "./mathUtils.js";

console.log(PI); // 3.14159
console.log(add(5, 3)); // 8
console.log(subtract(5, 3)); // 2

// E is NOT imported, so this would error:
// console.log(E); // ❌ Error: E is not defined
Named Exports Require Exact Names

Unlike default exports, named exports must be imported with their exact names:

// utils.js
export const name = "Alice";
export const age = 25;

// app.js
import { name, age } from "./utils.js"; // βœ… Correct
import { userName, age } from "./utils.js"; // ❌ Error! No 'userName' export

Renaming Imports/Exports with as​

Sometimes you need different names to avoid conflicts:

Rename When Importing:

mathUtils.js
export const add = (a, b) => a + b;
export const subtract = (a, b) => a - b;
app.js
// Rename during import
import { add as sum, subtract as minus } from "./mathUtils.js";

console.log(sum(5, 3)); // 8 (renamed from 'add')
console.log(minus(5, 3)); // 2 (renamed from 'subtract')

Rename When Exporting:

mathUtils.js
const add = (a, b) => a + b;
const subtract = (a, b) => a - b;

// Rename during export
export { add as sum, subtract as minus };
app.js
// Must use the exported names
import { sum, minus } from "./mathUtils.js";

console.log(sum(5, 3)); // 8
console.log(minus(5, 3)); // 2

Real-World Example: Utility Functions​

validators.js
export function isEmail(str) {
return str.includes("@");
}

export function isPhoneNumber(str) {
return /^\d{10}$/.test(str);
}

export function isZipCode(str) {
return /^\d{5}$/.test(str);
}

export const MIN_PASSWORD_LENGTH = 8;
export const MAX_USERNAME_LENGTH = 20;
app.js
import {
isEmail,
isPhoneNumber,
MIN_PASSWORD_LENGTH
} from "./validators.js";

console.log(isEmail("user@example.com")); // true
console.log(isPhoneNumber("1234567890")); // true
console.log(MIN_PASSWORD_LENGTH); // 8

Importing Everything with *​

You can import all named exports at once:

mathUtils.js
export const PI = 3.14159;
export const add = (a, b) => a + b;
export const subtract = (a, b) => a - b;
app.js
// Import everything into a namespace
import * as math from "./mathUtils.js";

console.log(math.PI); // 3.14159
console.log(math.add(5, 3)); // 8
console.log(math.subtract(5, 3)); // 2
When to Use *

Use import * when:

  • You need many exports from one file
  • You want a clear namespace (e.g., math.add, utils.format)
  • You want to avoid naming conflicts

CommonJS Export and Import​

CommonJS is an older module system. It uses a different syntax for Import and Export statements compared to ES6.

module.exports and require​

Check out the following example to understand how to export and import a module in CommonJS.

module.js
const message = "Hello World";
module.exports = message;

The module.exports object is used to export the module. It can be used to export a single value or multiple values from a module. In the above example, we have exported a single value, message, from the module.js file.

The require statement is used to import the exported module from another file. The syntax for importing a module in CommonJS is as follows:

import.js
const message = require("./module.js");
console.log(message); // Hello World

In the above example, the module.js file exports a single value, message, using the module.exports object. The import.js file then imports this value using the require statement. The require statement returns the value that was exported from the module.js file. This is kind of a default export in CommonJS.

tip
Export multiple values from a module using module.exports

The module.exports object can be used to export multiple values from a module. The syntax for exporting multiple values from a module is as follows:

module.js
const name = "John";
const age = 30;
function add(a, b) {
return a + b;
}

module.exports = {
name,
age,
add,
};

exports and require​

The exports object is used to export multiple values from a module. The syntax for exporting multiple values from a module is as follows:

module.js
const name = "John";
const age = 30;
function add(a, b) {
return a + b;
}

exports.name = name;
exports.age = age;
exports.add = add;

The require statement is used to import the exported module from another file. The syntax for importing a module in CommonJS is as follows:

import.js
const { name, age, add } = require("./module.js");
console.log(name, age); // John 30
console.log(add(2, 3)); // 5

In the above example, the module.js file exports multiple values, name, age, and add, using the exports object. The import.js file then imports these values using the require statement. The require statement returns an object that contains the exported values. We can then destructure the object to get the values.

Default vs Named Exports: When to Use Which? πŸ€”β€‹

AspectDefault ExportNamed Exports
How many?One per fileMultiple per file
Import nameAny name you wantMust match export name
Syntaxexport default Xexport { X, Y, Z }
Best forMain component/classUtilities, constants
Exampleexport default Userexport { add, subtract }

Practical Guidelines​

Use Default Export when:

// βœ… File has one main purpose
// Button.js
export default function Button() { /* ... */ }

// User.js
export default class User { /* ... */ }

// config.js
export default { apiUrl: "...", timeout: 5000 };

Use Named Exports when:

// βœ… File has multiple related utilities
// mathUtils.js
export const PI = 3.14159;
export function add(a, b) { return a + b; }
export function subtract(a, b) { return a - b; }

// validators.js
export function isEmail(str) { /* ... */ }
export function isPhone(str) { /* ... */ }
export function isZip(str) { /* ... */ }

Mixing Both (Advanced)​

You can use both default and named exports in the same file:

calculator.js
// Default export - main feature
export default class Calculator {
add(a, b) { return a + b; }
subtract(a, b) { return a - b; }
}

// Named exports - extras
export const PI = 3.14159;
export const E = 2.71828;
export function round(num) {
return Math.round(num);
}
app.js
// Import both
import Calculator, { PI, round } from "./calculator.js";

const calc = new Calculator();
console.log(calc.add(5, 3)); // 8
console.log(PI); // 3.14159
console.log(round(3.7)); // 4

Common Mistakes to Avoid πŸš¨β€‹

Mistake 1: Missing File Extension​

// ❌ Wrong (in browsers)
import { add } from "./utils";

// βœ… Right
import { add } from "./utils.js";

Mistake 2: Confusing Default and Named​

// utils.js
export const add = (a, b) => a + b; // Named export

// ❌ Wrong (trying to import named as default)
import add from "./utils.js";

// βœ… Right
import { add } from "./utils.js";

Mistake 3: Importing Non-Existent Exports​

// utils.js
export const add = (a, b) => a + b;

// ❌ Wrong (subtract doesn't exist)
import { add, subtract } from "./utils.js"; // Error!

// βœ… Right
import { add } from "./utils.js";

Mistake 4: Modifying Imports​

import { user } from "./data.js";

// ❌ Wrong (imports are read-only)
user = { name: "Bob" }; // Error!

// βœ… Right (if object, can modify properties)
user.name = "Bob"; // OK

Quick Reference Cheat Sheet πŸ“‹β€‹

// ────────── EXPORTING ──────────

// Default export (one per file)
export default function() { }
export default class User { }
export default { key: "value" }

// Named exports (multiple per file)
export const PI = 3.14;
export function add() { }
export class User { }

// Export multiple at once
const a = 1, b = 2;
export { a, b };

// Export with rename
export { a as alpha, b as beta };

// ────────── IMPORTING ──────────

// Default import
import MyName from "./file.js"

// Named imports
import { name, age } from "./file.js"

// Import with rename
import { name as userName } from "./file.js"

// Import all as namespace
import * as Utils from "./file.js"
// Use as: Utils.name, Utils.age

// Mix default + named
import DefaultThing, { namedThing } from "./file.js"

Conclusion​

Modules are essential for organizing modern JavaScript applications! We learned:

βœ… ES6 Modules - Modern import/export syntax βœ… Default Exports - One main export per file βœ… Named Exports - Multiple specific exports βœ… Import Renaming - Use as to rename βœ… CommonJS - Older require/module.exports (Node.js) βœ… Best Practices - When to use each pattern

Remember: Start with ES6 modules for new projects. They're the modern standard and work everywhere! πŸš€