class
ModuleGraph
class ModuleGraph
A further instantiation of ES module graphs in this global object.
Every graph that loads a file shares that file's parsed code and bytecode with every other graph and with the host, and for ES modules the JIT-compiled code too; each graph gets its own module-level state (top-level bindings, classes, closures), its own module registry for import / import(), its own require.cache (require(), import.meta.require() and createRequire() called from the graph's code load into it), its own import.meta, and its own values for the names in globals. Everything else — globalThis, process, intrinsics, builtin modules (so require("node:module")._cache is the host's cache), native addons, the event loop — is the global object's, shared: this runs instances of a program side by side, it is not a sandbox.
A graph has a context of its own for timers and I/O. Everything its code opens — timers, Bun.serve / Bun.listen servers, sockets, fetch() requests, watchers, child processes — belongs to the graph, and ModuleGraph.dispose closes all of it. The context follows the graph's code through await, timers, socket handlers and the listeners of what it made, the way AsyncLocalStorage stores do (creating the first graph turns that tracking on for the process). Code of the graph that the host calls directly runs in the host's context; use ModuleGraph.run to call it in the graph's.
const graph = new Bun.ModuleGraph({
globals: { process: Object.create(process, { env: { value: { NAME: "a" } } }) },
onError: (err, kind) => console.error(kind, err),
});
const app = await graph.import("./app.mjs"); // app.mjs's exports, for this graph
graph.run(() => app.start()); // what start() opens is the graph's
graph.dispose(); // and is closed here- readonly static current: undefined | ModuleGraph
The graph whose context the calling code is running in (what it opens now would belong to that graph), or
undefinedin the host's context. For host functions shared by several graphs, and for asserting that a call went through ModuleGraph.run. Closes everything the graph's code opened (and disposes any graph its code made), and drops the graph's modules:
graph.import()andgraph.run()fail from here on, the graph'srequire()throws, and modules that had not run yet never will.The graph is told nothing, like a worker that was terminated: no
closehandler,onExitor'error'event is called, and no promise is settled — one waiting on the graph's work (afetch(), a child'sexited, animport()still loading) stays pending. Microtasks andprocess.nextTickcallbacks it had already queued still run once; what they start reports nothing either. Objects the graph's code made (a socket, a worker, a stream) no longer work, for the host either.Not a sandbox: synchronous calls run to completion. Idempotent.
- specifier: string): Promise<T>;
Load
specifier(resolved againstprocess.cwd()when relative) and instantiate it and its dependencies into this graph, evaluating what has not been evaluated in this graph yet.The first module imported into a graph is its main module:
import.meta.mainis true in it and in no other module of the graph.@param specifiermodule specifier, as for
import()@returnsthe module's namespace object for this graph
- fn: (...args: A) => R,...args: A): R;
Call
fninside the graph's context: whatfnand everything it starts open belongs to the graph.Throws
ERR_INVALID_STATEonce the graph is disposed.@returnswhat
fnreturns