skip to content

Circular Dependencies

What happens when A imports B and B imports A: ESM gives you an uninitialized-binding error, CommonJS hands back a half-finished exports object. Interviewers ask you to predict the output for each system and then to break the cycle.

part ofJavaScriptoverview, primer and where to startread it →
on this pageshow

questions

4

In Node's CommonJS, a.js sets `exports.done = false`, then calls `require('./b.js')`, and b.js immediately calls `require('./a.js')` and reads `.done` on the result. What does b.js receive, and why is no error thrown?

level: middleimportance: should knowfreq 48%

basics

~20 s

b.js receives a.js's partially populated exports object: done is false, and anything a.js assigns after its require call is simply absent. CommonJS caches the module object before running the body, so the back-edge require returns whatever exists at that instant — silently.

open as a page

In a native ES module graph, main.js imports './a.js'; a.js starts with `import { fromB } from './b.js'` and then declares `export const fromA = 'A'`; b.js starts with `import { fromA } from './a.js'` and logs fromA at its top level. What happens when this runs, and why?

level: middleimportance: should knowfreq 45%

basics

~20 s

b.js evaluates first and throws ReferenceError: Cannot access 'fromA' before initialization. Linking already created the binding for a.js's const, but a.js's body has not run yet, so the binding is still in its temporal dead zone.

open as a page

A large JavaScript codebase intermittently sees an imported value arrive as undefined, or throws 'Cannot access before initialization', depending on which entry point loads first. How do you confirm an import cycle is the cause, and how do you break it?

level: seniorimportance: should knowfreq 33%

basics

~20 s

Map the import graph and look for a loop — a tool such as madge run with --circular, or ESLint's import/no-cycle rule, lists them mechanically. Then break the loop by extracting the shared code into a third module, or by inverting the dependency, rather than by reordering imports.

open as a page