Default Exports
A module can designate exactly one default export — the value a consumer gets when they import without braces. Defaults are common in React component files and many npm packages, where the module has one obvious “main thing.” But unlike named exports, a default export has no canonical name, which weakens autocomplete and refactoring. This page shows how to declare and consume default exports, how they interoperate with named exports, and why most modern TypeScript style guides lean toward named exports.
Declaring a default export
Use export default before a value, function, or class. There can be only one per module.
// logger.ts
export default class Logger {
log(message: string): void {
console.log(`[LOG] ${message}`);
}
}
You can also default-export an expression, a function, or an already-declared name:
// add.ts
export default function add(a: number, b: number): number {
return a + b;
}
// config.ts
const config = { retries: 3, timeout: 5_000 };
export default config;
You cannot put
export defaultin front of alet/conston the same line for multiple values, and you cannot default-export aninterfaceand use it as a value — defaults export one binding only.
Importing a default export
Import a default with no braces, and you choose the local name. Nothing forces it to match the original.
import Logger from "./logger.js";
import sum from "./add.js"; // could be named anything
import settings from "./config.js";
const l = new Logger();
l.log("ready");
console.log(sum(2, 3), settings.retries);
Because the import name is arbitrary, two files can name the same default differently — which is exactly why defaults are harder to track across a codebase.
Mixing default and named exports
A module can have one default export plus any number of named exports. This is the pattern many libraries use.
// api.ts
export default function request(url: string): Promise<Response> {
return fetch(url);
}
export const BASE_URL = "https://api.example.com";
export interface RequestOptions {
method?: "GET" | "POST";
}
Consumers combine both forms in a single import statement, with the default first:
import request, { BASE_URL, type RequestOptions } from "./api.js";
Why named exports are often preferred
Default exports trade discoverability and refactor-safety for a slightly shorter import. The table summarizes the trade-offs that lead many teams to standardize on named exports.
| Concern | Named export | Default export |
|---|---|---|
| Import name | Fixed; must match (or alias with as) | Arbitrary; chosen at each site |
| Editor autocomplete | Suggested by name on import | Not suggested — you type the name |
| Rename refactor | Updates all references | References must be fixed by hand |
| Re-export in barrels | export { x } from | Needs export { default as X } |
| Tree-shaking | Excellent | Excellent |
Because a default export has no intrinsic name, “find all references” and automated renames are less reliable, and barrels must rename the default explicitly:
// index.ts
export { default as Logger } from "./logger.js";
When defaults still make sense
Defaults are reasonable when a module genuinely represents a single thing and an ecosystem convention expects it — for example, a React component per file, or following a framework’s file conventions.
// Button.tsx
export default function Button({ label }: { label: string }) {
return <button>{label}</button>;
}
Even then, many style guides (and ESLint’s import/no-default-export) prefer named exports for consistency, so the choice is largely a team convention.
verbatimModuleSyntaxand CommonJS interop edge cases can makeexport defaultbehave differently fromexport =. If you target CommonJS, prefer named exports or test the emit. See Type-Only Imports & Exports.
Best Practices
- Default to named exports for application code — they are explicit and refactor-safe.
- Allow at most one default export per module, and only when the module has one clear purpose.
- Follow ecosystem conventions (e.g. one React component per file) where defaults are expected.
- Re-export defaults as named symbols in barrels:
export { default as Name } from. - Avoid renaming a default differently across files; pick one name and stick to it.
- Consider an ESLint rule (
import/no-default-export) to enforce a consistent policy.