Talk me through Node's module cache. And when does the whole singleton assumption stop holding?
The strong answer knows the cache keys on the resolved real path, lists the ways the singleton assumption breaks, and walks a circular require step by step
So the first time you require something, Node loads it, runs it, and sticks the module object in require.cache, keyed by the resolved filename I believe. After that, every require of the same file just hands back the cached exports object, nothing re-executes. That's why the pattern of creating a database pool at the top of a module works as a singleton, everyone who imports it shares the one pool. Circular dependencies don't error or anything, the module that joins the cycle just gets whatever the other one has exported so far, so you can end up with missing properties if you call things too early. You can also delete entries from require.cache to force a re-load, that's how some hot-reload tools do it. And ESM keeps its own cache, but it's the same practical effect, one execution per module, shared exports.