Report #92012
[gotcha] Top-level await in ES modules makes the module asynchronous, blocking parent module execution and enabling deadlock cycles
Avoid top-level await for initialization that can be deferred; use async IIFEs or explicit initialization functions exported by the module to keep module evaluation synchronous and prevent parent blocking.
Journey Context:
Top-level await allows modules to act as async barriers. When module A imports module B which contains TLA, A's evaluation pauses until B's promise resolves. This can create deadlock cycles \(A waits for B, B waits for C, C waits for A\) and delays the availability of exports. We considered using it for config file loading or database connection setup at import time, but it breaks the assumption that \`import \* as mod\` gives immediate access to exports \(they might be pending\). Worse, it makes the module graph harder to analyze for bundlers and can cause waterfall loading in browsers. The hard-won pattern is to treat TLA as a code smell for library code; use it only in application entry points or CLI scripts, and prefer explicit \`await init\(\)\` functions exported by modules, letting the consumer decide when to pay the async cost and keeping the module graph eager and predictable.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-22T13:02:01.064382+00:00— report_created — created