Export Default vs Named Exports in JavaScript
JavaScript ES6 modules provide two distinct mechanisms for sharing
code between files: export default and named exports. The
primary differences lie in the number of exports allowed per module, the
required import syntax, and naming flexibility. While a module can only
contain a single default export that can be imported using any arbitrary
name without curly braces, named exports allow multiple values per file
and require exact matching names enclosed in curly braces when
imported.
Number of Exports Allowed
- Default Export: A module can have only one
export default. It represents the main or primary value, function, or class provided by the file. - Named Exports: A module can contain zero, one, or multiple named exports. This is ideal for utility libraries or modules containing multiple related functions and constants.
Export Syntax
Named Exports: You can export variables, functions, or classes directly at declaration or by grouping them in an export clause at the bottom of the file.
// Inline named exports
export const API_URL = "https://api.example.com";
export function fetchData() { /* ... */ }
// Grouped named exports
const API_URL = "https://api.example.com";
function fetchData() { /* ... */ }
export { API_URL, fetchData };Default Export: You define a single default export
using the default keyword.
// Direct default export
export default function UserService() { /* ... */ }
// Or exporting an existing value
const UserService = () => { /* ... */ };
export default UserService;Import Syntax
The way you import values depends directly on how they were exported.
Importing Named Exports: Named exports require
destructuring syntax with curly braces {}. The names must
match the exported identifiers unless explicitly renamed with the
as keyword.
import { API_URL, fetchData } from './api.js';
import { fetchData as getData } from './api.js'; // RenamingImporting Default Exports: Default exports are imported without curly braces. Because there is only one default export, you can name the imported identifier whatever you prefer.
import UserService from './userService.js';
import CustomUserHandler from './userService.js'; // Valid: names can differCombining Both Approaches
A single module can combine both named exports and a default export.
// mathUtils.js
export const PI = 3.14159;
export function add(a, b) { return a + b; }
export default function calculateArea(radius) { return PI * radius * radius; }You can import them together in a single statement:
import calculateArea, { PI, add } from './mathUtils.js';Tooling, Refactoring, and Tree-Shaking
- Auto-completion and Refactoring: Named exports provide better IDE support. IDEs can automatically suggest imports, and renaming a named export across a codebase is more reliable because the identifier is fixed.
- Tree-Shaking: While modern bundlers handle both well, named exports make it easier for bundlers to statically analyze code and eliminate unused exports to reduce bundle size.
- Consistency: Default exports can lead to inconsistency across large teams since different developers might assign different names to the same imported module.
When to Use Which
- Use named exports when a module serves as a library of multiple utilities, constants, or related components. This enforces consistent naming and improves code navigability.
- Use
export defaultwhen a file has a single, clear responsibility—such as a specific React component, a configuration object, or a dedicated class.