Compile Ready
Module 10 · ES6+ Features

import / export

Advanced11m read6m practice17m total
importexportES ModulesNamed ExportsDefault Exports

Introduction

import and export are the declarations that make ES Modules work. Exports decide what a module exposes; imports decide which bindings another module consumes.

The syntax looks simple, but interviews probe details: named versus default exports, aliases, namespace imports, re-exports, barrels, live read-only bindings, and why static imports cannot be placed inside if blocks.

Why This Matters

Clear module boundaries are a production engineering skill. Good import/export structure improves bundle size, testability, dependency direction, and code review readability. It also prevents common mistakes such as default/named import mismatches and circular barrel dependencies.

Theory

Named exports

Named exports expose one or more bindings by name. Importers must use the exported name or an alias: import { formatDate as format } from './date.js'. Named exports are best when a module has several public utilities.

Default exports

A module can have one default export. Importers choose any local name: import Button from './Button.js'. Defaults are common for primary components or classes, but named exports often refactor better because tooling can track names more explicitly.

Namespace imports

import * as date from './date.js' collects the module namespace into an object-like value. It is useful when you want to group related exports, but it can make tree-shaking less obvious in some toolchains if overused.

Re-exports and barrels

A barrel file re-exports from several modules, often through export { Button } from './Button.js'. Barrels improve public APIs but can create accidental cycles or pull in side effects if used carelessly.

Static import constraints

Static imports must be top-level. Use dynamic import() when you need conditional or lazy loading. Static imports are hoisted and linked before the module body evaluates.

Visual Diagrams

Export surface and import choices
date.js exports:
  formatDate
  parseDate
  default locale

consumer choices:
  named import       -> one binding by exported name
  default import     -> the module's primary value
  namespace import   -> object-like namespace of exports
  re-export          -> pass bindings through another module

Choosing the right import/export form makes module APIs easier to read and optimize.

Code Examples

Named, default, alias, and namespace imports

This read-only sample uses separate files. Static imports belong at the top level of an ES module.

Loading…

Re-exports and barrel files

Barrels define a stable public API, but avoid hiding large side-effectful dependency graphs behind one file.

Loading…

Dynamic import for conditional loading

Static imports are top-level. When code must load conditionally or lazily, use dynamic import in an async boundary.

Loading…

Playground

Loading editor…
Console

Press Run to execute the code and see output here.

Output Prediction

Predict the output #1

javascript
1let internal = 1;
2const namespace = {};
3
4Object.defineProperty(namespace, 'value', {
5 get: function () {
6 return internal;
7 }
8});
9
10const snapshot = namespace.value;
11internal = 2;
12
13console.log(snapshot);
14console.log(namespace.value);

Coding Exercises

Classify import requests

Medium

Implement classifyImports(requests) where each request is an object with kind equal to 'named', 'default', or 'namespace'. Return a count object with keys named, default, and namespace.

Interview Questions

1What is the difference between named and default exports?

A module can have many named exports, imported by their exported names or aliases. A module can have only one default export, imported with any local name. Named exports usually improve refactoring and discoverability; default exports are convenient for a module's single primary value.

Asked at:VercelMetaMicrosoft
2Can you put a static import inside an `if` statement?

No. Static import declarations must be at the top level of an ES module so the module graph can be linked before evaluation. For conditional or lazy loading, use dynamic import().

Follow-ups

  • What does a namespace import contain?
  • When can barrel files hurt a codebase?
3Why might a named/default import mismatch fail?

Named imports must match named exports exactly unless aliased. Default imports read the module's default export. Importing { Button } from a module that only has export default Button asks for a named export that does not exist.

Quiz

1. How many default exports can one ES module have?

2. Which statement about static imports is true?

Summary

  • Named exports expose bindings by name; default export exposes one primary value.
  • Imports can alias named exports and can collect exports through namespace imports.
  • Re-export barrels shape public APIs but can hide dependency and side-effect costs.
  • Static imports must be top-level; dynamic `import()` handles conditional or lazy loading.
  • Imported ESM bindings are live read-only views.

Cheat Sheet

Named: export const x = 1; import { x } from './m.js'.

Alias: import { x as value } from './m.js'.

Default: export default Thing; import Thing from './Thing.js'.

Namespace: import * as api from './api.js'.

Re-export: export { Button } from './Button.js'.

Dynamic: const mod = await import('./heavy.js').