Lesson guide
Learning objectives
- Explain the main purpose of Dynamic imports in JavaScript.
- Identify the syntax, APIs, or concepts introduced in this lesson.
- Use the examples to predict how JavaScript will behave before you run similar code.
- Connect this topic to nearby lessons in Modules.
Real-world context
This lesson matters when you need to recognize where Dynamic imports fits into real JavaScript programs. Export and import statements that we covered in previous chapters are called “static”.
Key ideas
- Dynamic imports is part of the Modules chapter, so it builds on the surrounding concepts rather than standing alone.
- Read each code example in two passes: first for the result, then for the rule that explains the result.
- When a section compares similar features, focus on the condition that makes you choose one feature over another.
Key terms
- Dynamic imports
- Dynamic
- imports
- Modules
- JavaScript
Export and import statements that we covered in previous chapters are called “static”. The syntax is very simple and strict.
First, we can’t dynamically generate any parameters of import.
The module path must be a primitive string, can’t be a function call. This won’t work:
import ... from getModuleName();
Second, we can’t import conditionally or at run-time:
if(...) { import ...; // Error, not allowed! } { import ...; // Error, we can't put import in any block }
That’s because import/export aim to provide a backbone for the code structure. That’s a good thing, as code structure can be analyzed, modules can be gathered and bundled into one file by special tools, unused exports can be removed (“tree-shaken”). That’s possible only because the structure of imports/exports is simple and fixed.
But how can we import a module dynamically, on-demand?
The import() expression
The import(module) expression loads the module and returns a promise that resolves into a module object that contains all its exports. It can be called from any place in the code.
We can use it dynamically in any place of the code, for instance:
let modulePath = prompt("Which module to load?"); import(modulePath) .then(obj => <module object>) .catch(err => <loading error, e.g. if no such module>)
Or, we could use let module = await import(modulePath) if inside an async function.
For instance, if we have the following module say.js:
// 📁 say.js export function hi() { alert(`Hello`); } export function bye() { alert(`Bye`); }
…Then dynamic import can be like this:
let {hi, bye} = await import('./say.js'); hi(); bye();
Or, if say.js has the default export:
// 📁 say.js export default function() { alert("Module loaded (export default)!"); }
…Then, in order to access it, we can use default property of the module object:
let obj = await import('./say.js'); let say = obj.default; // or, in one line: let {default: say} = await import('./say.js'); say();
Here’s the full example:
Result
say.js
index.html
open in a new windowedit in the sandbox
Click me
export function hi() { alert(`Hello`); } export function bye() { alert(`Bye`); } export default function() { alert("Module loaded (export default)!"); } ```javascript import ... from getModuleName(); // Error, only from "string" is allowed ```markup <!doctype html> <script> async function load() { let say = await import('./say.js'); say.hi(); // Hello! say.bye(); // Bye! say.default(); // Module loaded (export default)! } </script> <button onclick="load()">Click me</button>
Please note:
Dynamic imports work in regular scripts, they don’t require script type="module".
Please note:
Although import() looks like a function call, it’s a special syntax that just happens to use parentheses (similar to super()).
So we can’t copy import to a variable or use call/apply with it. It’s not a function.
Common mistakes
- Skipping the small examples and then missing the exact rule that Dynamic imports depends on.
- Copying code without changing one value at a time to see which part controls the result.
- Treating similar-looking syntax or APIs as interchangeable before checking their edge cases.
Summary
- Dynamic imports gives you one more piece of the JavaScript mental model.
- The examples in this lesson are the quickest way to check whether the rule is clear.
- Revisit the key terms when you meet the same idea in later chapters.
Predict
Before running this dynamic-import check, predict the four output lines. It uses import(modulePath) with a computed module URL, reads named and default exports from the module object, and catches a loading/evaluation error.
Reveal explanation
The output is Hello, John!, default loaded, broken module, and Bye, Ann!. Unlike static import ... from "...", import(modulePath) accepts a value computed at runtime and returns a promise. The fulfilled value is a module object: named exports are properties such as hi and bye, while the default export is available as default. If the module cannot load or throws while evaluating, the promise rejects and try...catch around await import(...) handles it.
Try it
Change exportName to "hi", then predict the final line and explain why bracket access can choose an export at runtime.
Practice
- Rewrite one example from this lesson without looking at the original, then run it and compare the result.
- Change one input, operator, method call, or option in a code sample and predict what will happen before running it.
- Explain Dynamic imports in your own words as if you were reviewing it with another learner.
Keep learning
Continue with Proxy and Reflect when you are ready for the next lesson.