Skip to content

Named Exports and Imports

The most common way to share code between modules is with named exports. You explicitly mark which values, functions, or classes a file makes available to other files.

Add the export keyword before any declaration:

expense.js
export class Expense {
static CATEGORIES = ['Food', 'Transport', 'Health', 'Entertainment', 'Other'];
#id;
#createdAt;
constructor({ id, description, amount, category, date, createdAt } = {}) {
if (!description || description.trim() === '') throw new Error('Description is required');
if (typeof amount !== 'number' || amount <= 0) throw new Error('Amount must be positive');
this.#id = id ?? crypto.randomUUID();
this.#createdAt = createdAt ?? Date.now();
this.description = description.trim();
this.amount = amount;
this.category = category ?? 'Other';
this.date = date ?? new Date().toISOString().split('T')[0];
}
get id() { return this.#id; }
get createdAt() { return this.#createdAt; }
format() { return `${this.description}: $${this.amount.toFixed(2)}`; }
isInCategory(c) { return this.category.toLowerCase() === c.toLowerCase(); }
toJSON() {
return { id: this.#id, description: this.description, amount: this.amount,
category: this.category, date: this.date, createdAt: this.#createdAt };
}
static fromJSON(data) { return new Expense(data); }
static isValidCategory(c) { return Expense.CATEGORIES.includes(c); }
}

You can export functions, classes, constants, and objects — any value:

storage.js
export function saveExpenses(expenses) {
localStorage.setItem('expenses', JSON.stringify(expenses.map(e => e.toJSON())));
}
export function loadExpenses() {
const raw = localStorage.getItem('expenses');
if (!raw) return [];
return JSON.parse(raw).map(data => Expense.fromJSON(data));
}

In the file that needs these values, use import { name } from './path':

main.js
import { Expense } from './expense.js';
import { saveExpenses, loadExpenses } from './storage.js';
const expenses = loadExpenses();
const coffee = new Expense({ description: 'Coffee', amount: 4.50, category: 'Food' });
expenses.push(coffee);
saveExpenses(expenses);

Key rules:

  • The imported name must exactly match the exported name (including case)
  • The path must start with ./ or ../ — not just the filename
  • Include the .js extension (required by native ES modules in the browser)

A file can export as many names as it needs:

utils.js
export function formatCurrency(amount) {
return `$${amount.toFixed(2)}`;
}
export function formatDate(dateString) {
return new Date(dateString).toLocaleDateString('en-US', {
year: 'numeric', month: 'short', day: 'numeric',
});
}
export const DEFAULT_CURRENCY = 'USD';
main.js
import { formatCurrency, formatDate, DEFAULT_CURRENCY } from './utils.js';

Import only what you need — leaving out unused names does not cause errors.

You can rename an import with as:

import { formatCurrency as fmt } from './utils.js';
console.log(fmt(12.75)); // '$12.75'

This is useful when two modules export names that would otherwise conflict.

A module can import from one file and re-export for others to use. This is common in index files that collect and re-export everything from a folder:

index.js
export { Expense } from './expense.js';
export { saveExpenses, loadExpenses } from './storage.js';
export { formatCurrency, formatDate } from './utils.js';

Now other files can import from ./index.js instead of knowing which specific file each name lives in.

  1. Create expense.js and move your Expense class into it with a named export.
  2. Create utils.js and export two functions: formatCurrency(amount) and formatDate(dateString).
  3. Create main.js that imports Expense from ./expense.js and both utilities from ./utils.js.
  4. Create a few Expense instances in main.js and log formatCurrency(expense.amount) for each.
  5. Confirm the app works by opening index.html in a local server.
  • export before a declaration makes it available to other modules.
  • import { name } from './file.js' brings a named export into the current file.
  • Names must match exactly; paths must start with ./ or ../ and include .js.
  • Import only what you need — unused names are not imported.
  • Rename with as to avoid name collisions.