Default vs. Named Exports: Organizing Your Modules
In the previous lesson, we learned about import and export for making code modular. Now, let's dive into the two main types of exports: named exports and default exports, understanding their syntax, behavior, and when to use each.
1. Named Exports (Recap)
Named exports allow you to export multiple values from a module. Each value is exported by its specific name, and when you import them, you must refer to them by those same names (though you can alias them).
Characteristics:
- Multiple per Module: A single file can have many named exports.
- Specific Name: You
exportitems by their exact names (e.g.,export const myVar;,export function myFunction;). - Curly Braces for Import: When importing, you must use curly braces
{}to specify which named exports you want (e.g.,import { myVar, myFunction } from './module.js';). - Renaming on Import: You can rename a named import using
as(e.g.,import { myFunction as newFunctionName } from './module.js';).
Example:
// --- file: namedExports.js ---
export const GREETING = 'Hello, World!';
export function sayHello(name) {
return GREETING + ' My name is ' + name + '.';
}
export class Person {
constructor(name) {
this.name = name;
}
introduce() {
return 'I am ' + this.name + '.';
}
}
// --- file: main.js ---
import { sayHello, Person } from './namedExports.js';
import { GREETING as welcomeMessage } from './namedExports.js'; // Renaming GREETING
console.log('--- Named Exports Demo ---');
console.log('');
console.log('Imported GREETING (renamed): ' + welcomeMessage);
console.log('Using imported sayHello: ' + sayHello('Alice'));
const bob = new Person('Bob');
console.log('Using imported Person class: ' + bob.introduce());
Output:
--- Named Exports Demo ---
Imported GREETING (renamed): Hello, World!
Using imported sayHello: Hello, World! My name is Alice.
Using imported Person class: I am Bob.
2. Default Exports
A module can have only one default export. This is typically used when the module's primary purpose is to export a single entity, making it the "main thing" the module provides.
Characteristics:
- One per Module: You can have only one
export defaultstatement per file. - No Name Required on Export: You export an expression directly (e.g.,
export default myFunction;orexport default class MyClass;). The name is typically derived from the importing module. - No Curly Braces for Import: When importing, you do not use curly braces. You can give the default export any name you like when importing it (e.g.,
import myName from './module.js';). This is very flexible. - Often for Single Purpose: Best used for modules that encapsulate a single primary function, class, or object.
Syntax for Default Export:
// --- file: myUtility.js ---
// Exporting a default function
export default function capitalize(str) {
if (!str) return '';
return str.charAt(0).toUpperCase() + str.slice(1);
}
// You can also export a variable/constant as default
// const DEFAULT_AGE = 30;
// export default DEFAULT_AGE;
// Or a class as default
// export default class Greeter {
// greet(name) { return 'Hello ' + name; }
// }
Importing a Default Export:
// --- file: app.js ---
// Import the default export and give it the name 'toCapitalCase'
import toCapitalCase from './myUtility.js';
// You can give it any name:
// import capText from './myUtility.js';
console.log('--- Default Exports Demo ---');
console.log('');
console.log('Original: "javascript"');
console.log('Capitalized: ' + toCapitalCase('javascript'));
console.log('');
console.log('Original: "modules"');
console.log('Capitalized: ' + toCapitalCase('modules'));
Output:
--- Default Exports Demo ---
Original: "javascript"
Capitalized: Javascript
Original: "modules"
Capitalized: Modules
3. Mixing Default and Named Exports
It's entirely possible and common for a single module to provide both a default export (its primary offering) and several named exports (supporting utilities, constants, etc.).
When importing from such a module, you combine the two syntaxes: the default import (without braces) followed by named imports (with braces).
Example: Mixed Exports
// --- file: userUtils.js ---
export const DEFAULT_USER_ID = 1;
export const MAX_USERNAME_LENGTH = 20;
export function validateEmail(email) {
// Very basic email validation
return email.includes('@') && email.includes('.');
}
// The main utility function of this module
export default function getUserProfile(userId) {
return {
id: userId,
name: 'User ' + userId,
email: 'user' + userId + '@example.com'
};
}
// --- file: profilePage.js ---
// Importing the default export (getUserProfile) and named exports (DEFAULT_USER_ID, validateEmail)
import getProfile, { DEFAULT_USER_ID, validateEmail, MAX_USERNAME_LENGTH } from './userUtils.js';
console.log('--- Mixed Exports Demo ---');
console.log('');
const user1Profile = getProfile(DEFAULT_USER_ID);
console.log('Default user profile: ' + JSON.stringify(user1Profile));
console.log('');
const emailToValidate = 'test@example.com';
console.log('Is "' + emailToValidate + '" a valid email? ' + validateEmail(emailToValidate));
console.log('');
console.log('Max username length allowed: ' + MAX_USERNAME_LENGTH);
// Example of importing all named exports as a namespace, alongside the default
import MainProfileFetcher, * as Utils from './userUtils.js';
console.log('');
console.log('--- Using mixed namespace import ---');
console.log('Namespace user ID: ' + Utils.DEFAULT_USER_ID);
console.log('Namespace email validation: ' + Utils.validateEmail('another@test.net'));
console.log('Main fetcher (same as getProfile): ' + JSON.stringify(MainProfileFetcher(2)));
Output (partial for brevity):
--- Mixed Exports Demo ---
Default user profile: {"id":1,"name":"User 1","email":"user1@example.com"}
Is "test@example.com" a valid email? true
Max username length allowed: 20
--- Using mixed namespace import ---
Namespace user ID: 1
Namespace email validation: true
Main fetcher (same as getProfile): {"id":2,"name":"User 2","email":"user2@example.com"}
4. When to Use Which Type of Export
| Feature | Named Exports (export const name;) | Default Export (export default expr;) |
|---|---|---|
| Quantity | Multiple per module | Only one per module |
| Naming | Must import by exported name (can be aliased with as) | Can be imported with any name |
| Import Syntax | import { name } from './module.js'; | import anyName from './module.js'; |
| Use Case | Exporting multiple functions, constants, or components. Providing a "library" of related items. | Exporting the "main" entity of a module, typically a single class, function, or object. |
| Clarity | Forces specific naming, making it clear what's imported. | Can lead to inconsistent naming across projects if not careful. |
Choosing between named and default exports depends on the logical structure and intended use of your module. Named exports are great for utility files, while default exports are often favored for components (e.g., in React) or modules representing a single, distinct concept.

