TypeScript 5.9 introduced support for import defer, a newer JavaScript proposal that lets a module be loaded without immediately running it. That sounds tiny, but it matters when a module is expensive or has side effects you do not always need.

This guide explains the idea without turning it into language-spec homework.

Quick answer

import defer lets you import a module namespace now, but delay evaluating that module until you actually use it.

normal imports vs deferred imports

Normal static imports are evaluated before your module runs. That is usually good because dependencies are ready and predictable.

Deferred imports are different. They can help when a module is only needed in a specific branch, but you still want a static-looking import shape instead of fully dynamic import().

Import style What happens
import x from "./x" Dependency is loaded and evaluated before the current module runs
await import("./x") Dependency is loaded later at runtime
import defer * as x from "./x" Module namespace is available, but evaluation waits until usage

small example

import defer * as reportTools from "./expensive-report-tools.js";

export function maybeBuildReport(userRole: string) {
  if (userRole !== "admin") {
    return "No report needed";
  }

  return reportTools.buildReport();
}

In this shape, the reporting module does not need to execute for the non-admin path. That can matter if the module does expensive setup, reads large data, registers side effects, or imports other heavy modules.

when it is useful

The best use case is not “make every import deferred.” That would make code harder to reason about.

It is useful when a dependency is expensive and used rarely, but you still want a static import structure. For example:

  • Admin-only tools inside a large dashboard.
  • Debug or diagnostics modules.
  • Optional reporting and export logic.
  • Heavy visualization helpers.
  • Code that should avoid side effects until a branch is actually used.

what it does not fix

import defer is not a magic performance button. If the user always touches the deferred module during startup, you simply moved the cost slightly later.

It also does not replace good architecture. If a module has surprising side effects, the better long-term fix may be to remove those side effects or move them behind explicit functions.

practical checklist

  • Use normal imports by default.
  • Consider import defer only for expensive or side-effect-heavy modules.
  • Measure startup or interaction performance before and after the change.
  • Keep deferred modules easy to identify.
  • Avoid using it just because it is new.

Common mistakes

The first mistake is confusing deferred evaluation with lazy loading in every environment. Runtime support and bundler behavior matter, so check your actual target.

The second mistake is using it to hide messy module design. If importing a file does too much work, ask why that work happens at import time.

The third mistake is making debugging harder. Deferred work happens later, so errors may appear closer to the first use rather than during startup.

How to explain this in an interview

Say:

import defer helps delay module evaluation for code paths that are not always used. I would use it carefully for expensive optional modules, then measure whether it improves the real user path.

That answer shows you understand the feature and the tradeoff.

Sources checked

Final takeaway

import defer is useful when evaluation timing matters. Most code should keep normal imports, but expensive optional modules may benefit from being evaluated only when they are really needed.