JavaScript Modules: import and export Explained
SkillVeris Team
Engineering Team

JavaScript modules let you split code across files, exporting values from one file and importing them into another with export and import.
In this guide, you'll learn:
- Named exports let a file share many values by name; a default export shares one main value per file.
- import statements are static and hoisted, so the module graph is resolved before any code runs.
- ES modules (import/export) are the standard today; CommonJS (require/module.exports) is the older Node system.
- Modules have their own scope, so variables do not leak into the global namespace.
1What Are JavaScript Modules?
JavaScript modules are a way to split your code across multiple files, where each file explicitly exports the values it wants to share and other files import them. This keeps code organised, reusable, and free of the global-namespace clashes that plagued older scripts. The modern standard, ES modules, uses the export and import keywords built into the language.
Every module has its own private scope. A variable declared in one file is invisible to others unless you export it, and importing brings in only what you ask for. This explicit wiring makes large projects far easier to reason about, because you can see exactly where each value comes from.
2Named Exports
Named exports let a single file share as many values as you like, each under its own name. You either mark declarations with export or list them at the bottom. When importing, you use matching names in curly braces, which keeps the connection between files explicit and searchable.
- export function add(a, b) { return a + b } # inline named export
- export const PI = 3.14159 # export a constant
- export { add, PI } # or list exports together
- import { add, PI } from './math.js' # import by name
3Default Exports
A default export marks the single main thing a file provides. A module can have at most one default export, and the importing file chooses any name for it — no curly braces required. This suits files built around one central function, class, or component.
- export default function Button() { } # one default per file
- import Button from './Button.js' # name it whatever you like
- import MyButton from './Button.js' # same export, different local name
💡Pro Tip
Many teams prefer named exports even for single values because the import name stays consistent across the codebase, which makes searching and refactoring easier.
4Different Ways to Import
import is flexible. You can bring in named exports, a default, both at once, everything under a namespace, or run a module purely for its side effects. Knowing the forms helps you read any codebase and pick the clearest option for each situation.
- import { add } from './math.js' # a named export
- import Button from './Button.js' # the default export
- import Button, { variants } from './Button.js' # default plus named
- import * as math from './math.js' # everything as a namespace object
- import './styles.css' # side-effect import, no bindings
5ES Modules vs CommonJS
You will meet two module systems. ES modules, with import and export, are the language standard and work in browsers and modern Node. CommonJS, with require and module.exports, is the older Node system still common in existing packages. They differ in more than syntax.
ES module imports are static and resolved before execution, which enables features like tree-shaking to drop unused code. CommonJS requires run synchronously at call time. Node supports both, but new projects generally standardise on ES modules, often by setting type to module in package.json.
Quick Syntax Comparison
The two systems express the same idea differently, and mixing them in one project can cause friction, so pick one where you can.
ESM: export const x = 1 / import { x } from './file.js'
CJS: module.exports = { x } / const { x } = require('./file')6Dynamic Imports and Code Splitting
Alongside the static import statement, JavaScript offers a dynamic import() that loads a module on demand and returns a promise. Because it runs at call time rather than up front, you can defer loading heavy code until the moment a user actually needs it.
This underpins code splitting in modern apps. A route, a modal, or a rarely-used feature can live in its own chunk that only downloads when triggered, keeping the initial page fast. Bundlers recognise dynamic import and automatically split the code for you.
- const module = await import('./chart.js') # loads on demand
- button.addEventListener('click', async () => {
- const { openEditor } = await import('./editor.js') # deferred load
- openEditor()
- })
7Best Practices for Organising Modules
Good module habits keep a project navigable as it grows from a few files to hundreds. These guidelines apply whether you are building a library or an app.
- Keep modules small and focused on one responsibility.
- Prefer named exports for consistency and easier refactoring across the codebase.
- Include the file extension in relative import paths for native ES modules in the browser and Node.
- Avoid circular imports; if two files import each other, extract the shared part into a third.
- Group related modules into folders with a clear entry point rather than one giant file.
⚠️Watch Out
Circular dependencies can leave an import as undefined at the moment it is used. If you hit a mysterious undefined import, check whether two modules depend on each other.
8Key Takeaways
Modules are the backbone of well-structured JavaScript, and the rules are compact.
- export shares values from a file; import brings them into another.
- Named exports share many values by name; a default export shares one main value.
- Imports are static and resolved before code runs, enabling tree-shaking.
- ES modules are the standard; CommonJS with require is the older Node system.
- Keep modules small and focused, and avoid circular dependencies.
9Frequently Asked Questions
Q: What is the difference between named and default exports? A: A file can have many named exports, imported by their exact names in curly braces, and at most one default export, imported without braces under any name you choose. Named exports aid consistency; defaults suit a file's single main value.
Q: What is the difference between ES modules and CommonJS? A: ES modules use import and export, are the language standard, and resolve statically before running. CommonJS uses require and module.exports, is the older Node system, and loads synchronously at runtime. Node supports both.
Q: Why do I need the .js extension in imports? A: Native ES modules in the browser and in Node's ESM mode require the full file path including the extension. Bundlers like Vite or webpack often let you omit it, but native resolution does not.
Q: What causes a circular import problem? A: When two modules import each other, one may run before the other has finished defining its exports, leaving an import undefined at use time. The fix is to move the shared code into a separate module both can import.
Related Reading
Get The Print Version
Download a PDF of this article for offline reading.
About the Publisher
SkillVeris Team
Engineering Team
Our engineering writers turn abstract code concepts into hands-on, project-driven learning experiences.
View all postsRelated Posts
Never miss an update
Get the latest tutorials and guides delivered to your inbox.
No spam. Unsubscribe anytime.