A module containing await outside any function has [[HasTLA]] set. Its body runs as an async function body: the module's evaluation promise stays pending until the body finishes.
What that does to the graph:
- Dependents wait. A module that imports an async module can't run until the dependency's promise fulfills. This is transitive: a synchronous module that depends on an async one is deferred too. The entry module's own code runs last.
- Siblings overlap. Evaluation still walks the graph depth-first. When it reaches an async module it starts that body, and when the body hits its first
awaitit moves on to the next sibling without waiting. Two independent modules that each await a timer run concurrently, so the total delay is the longest one, not the sum. - Order is preserved where it matters. A dependent never runs before its dependencies. Among modules that become ready at the same time, they run in the order evaluation first reached them.
- Failure propagates. If the awaited promise rejects, the module's evaluation fails and so does every module that depends on it. A static
importof it leaves the program with that error;import()of it rejects. - Never-settling await. The graph never finishes. Node.js prints a warning and exits with code 13 once nothing else keeps the event loop alive.
require() is synchronous, so it can't wait. In Node.js 24 require(esm) works only when no module in the graph has top-level await; otherwise it throws ERR_REQUIRE_ASYNC_MODULE and you use import().
Top-level await is only for modules. In a classic script or CommonJS file, await is an ordinary identifier outside async functions.