Default Exports vs Named Exports

Default and named exports differ in syntax, import semantics, and how module APIs are consumed. A module can have one default export and multiple named exports, and the corresponding import syntax is different.

A named export gives a value an explicit exported name. You create one with `export const`, `export function`, `export class`, or an `export { name }` statement, and imports normally use the same exported identifier inside braces, such as `import { add } from './math.js'`.

A default export represents the module's primary exported value. A module can have at most one default export, written with `export default`. The importer can choose the local name, so `export default function add() {}` can be imported as `import calculate from './math.js'`.

The two forms also differ when importing several values. Named imports use braces and can be combined: `import { add, subtract } from './math.js'`. A default import does not use braces, and it can be combined with named imports: `import calculate, { format } from './module.js'`.

Named exports can be aliased during import with `import { add as sum } from './math.js'`. Default exports do not require an alias because the importing code directly chooses the local binding name. This makes default exports convenient for a module centered around one primary value, while named exports make individual API names explicit.

You can also import an entire module namespace with `import * as math from './math.js'`; its named exports become properties such as `math.add`, while the default export is available as `math.default`. Namespace imports are useful when you want to access several exports through one module object.

Key points

Interview questions

What is the difference between a default export and a named export?

A named export has an explicit exported identifier and is normally imported with braces. A default export is the module's single default value and is imported without braces. The local name of a default import can be chosen by the importer. A module may have multiple named exports but only one default export.

How would you import a default export and two named exports from the same module?

Put the default import first, followed by a comma and a braced list of named imports. For example, `import App, { Button, Input } from './ui.js'`. The default binding can have any local name, while `Button` and `Input` refer to their corresponding named exports unless aliases are specified.

Can you rename a named import?

Yes. Use the `as` keyword inside the import braces, such as `import { add as sum } from './math.js'`. `add` is the exported name, while `sum` is the local binding used by the importing module. This is useful when two modules expose the same name or when a local name is clearer.

Can a JavaScript module have both default and named exports?

Yes. A module may provide one default export alongside any number of named exports. For example, a component could be the default export while helper functions are named exports. Consumers can import the default value, named values, or both depending on what they need.

What does `import * as utils from './utils.js'` do?

It creates a module namespace binding named `utils`. The namespace exposes the module's exported bindings as properties, such as `utils.format` for a named export. If the module has a default export, it is represented as `utils.default`. This approach is useful when code intentionally wants to group access to many exports under one namespace.