Skip to main content

Dynamic import import()

1. What dynamic import is

import() is a loader function that lets you import a module at runtime, rather than statically at the top of a file.

Unlike regular import, which only works at the top level and is parsed synchronously at startup, import():

  • can be called anywhere in the code (for example, inside an if, a function, a handler);
  • returns a Promise that resolves to the module's exports object.

2. Syntax

javascript
const module = await import('./file.js');

or with .then():

javascript
import('./file.js').then((module) => { console.log(module); });

3. An example in Node.js (ESM)

math.js

javascript
export function add(a, b) { return a + b; } export function multiply(a, b) { return a * b; }

app.mjs

javascript
const { add } = await import('./math.js'); console.log(add(2, 3)); // 5

Works when:

  • your project is ESM ("type": "module" in package.json),
  • or the file has the .mjs extension.

4. An example with conditional loading

javascript
if (process.env.NODE_ENV === 'production') { const analytics = await import('./analytics.js'); analytics.init(); } else { console.log('Analytics disabled in development mode'); }

analytics.js won't load until the condition is true. That saves resources, a great technique for lazy-loading.

5. An example inside a function

javascript
async function loadAndUseModule() { const { greet } = await import('./greetings.js'); greet('Tim'); } loadAndUseModule();

greetings.js

javascript
export function greet(name) { console.log(`Hello, ${name}!`); }

6. Importing the whole module

javascript
const math = await import('./math.js'); console.log(math.add(2, 2)); console.log(math.multiply(2, 3));

math holds every export:

javascript
{ add: [Function: add], multiply: [Function: multiply] }

7. Importing via a variable

Unlike static import, dynamic import() can use variables:

javascript
const moduleName = './features/' + process.argv[2] + '.js'; const feature = await import(moduleName); feature.run();

This isn't possible with regular import, since it requires a static path:

javascript
import './' + path; // A syntax error

8. Importing JSON files (Node.js 20+)

Node.js now lets you import JSON via import():

javascript
const data = await import('./config.json', { assert: { type: 'json' } }); console.log(data.default);

assert is required:

  • { type: 'json' } tells Node.js to load the JSON as a module.

9. Dynamically importing CommonJS modules

If you're in an ESM project but want to import a CommonJS module (the old require):

javascript
const { readFileSync } = await import('fs'); const chalk = await import('chalk'); console.log(chalk.default.green('OK!'));

Node.js automatically "wraps" the CJS module, so it's available through default by default.

10. Importing inside a loop

Dynamic import is useful for bulk loading modules:

javascript
const features = ['auth', 'billing', 'analytics']; for (const f of features) { const mod = await import(`./modules/${f}.js`); mod.init?.(); }

11. Example: lazy loading in practice

routes.mjs

javascript
export async function handleRoute(route) { if (route === '/admin') { const admin = await import('./routes/admin.mjs'); return admin.handler(); } const home = await import('./routes/home.mjs'); return home.handler(); }

This is an ideal pattern for large servers (Express, Fastify, Next.js SSR):

  • only the needed handlers get loaded;
  • no wasted memory at runtime.

12. Features and differences from require()

Criterionrequire() (CJS)import() (ESM)
LoadingSynchronousAsynchronous (Promise)
ContextCommonJSES Modules
CachingYesYes
Live bindingsNoYes
Can be called anywhereYesYes
Supports awaitNoYes
In browsersNoYes

13. A combined example (Node.js + ESM)

package.json

javascript
{ "type": "module" }

app.js

javascript
async function start() { const env = process.env.NODE_ENV || 'dev'; const { default: config } = await import(`./config.${env}.js`); console.log('Config loaded:', config); } start();

config.dev.js

javascript
export default { db: 'sqlite', debug: true };

config.prod.js

javascript
export default { db: 'postgres', debug: false };

→ at startup, the correct config is picked up with no redundant imports.

14. Under the hood

When import() is called, Node.js:

  1. Parses the URL (including relative and absolute ones);
  2. Loads the module asynchronously;
  3. Caches it;
  4. Returns a Promise that resolves to the exports object.

In other words, import() ≈ a "lazy" version of import plus await require().

Quick summary

What it doesReturnsWhen it runs
import()A Promise with the module's exportsAt runtime
import (static)Instantly links the module during parsingBefore the code runs

In one sentence

Dynamic import (import()) is an asynchronous way to load ES Modules "on the fly", returning a Promise with the exports and enabling conditional, lazy, or parameterized code loading at runtime.

Short Answer

Interview ready
Premium

A concise answer to help you respond confidently on this topic during an interview.