The Bug That Passes Every Toolchain Check: Circular Dependencies in JavaScript
A circular dependency is one of the few bugs that passes every check your toolchain runs. TypeScript compiles it cleanly. The tests pass. The build succeeds. The app ships. And somewhere deep in your import graph, a developer is staring at a TypeError: X is not a constructor that disappears the moment they add a console.log . Here are the three patterns that create them, what Node.js, webpack, Rollup, and esbuild actually do with them — they don't solve the problem, they each make a different tradeoff — and how to stop them from forming. What a circular dependency actually is A circular dependency exists when module A imports from module B, which imports — directly or transitively — from module A. // user.service.ts import { formatUser } from ' ./user.utils ' ; // user.utils.ts import { UserService } from ' ./user.service ' ; // ← closes the loop Neither developer planned this. user.service.ts needed a formatter. user.utils.ts needed the service type for a helper added three sprints later. Nobody saw the cycle form — they just saw two reasonable imports. This is how every circular dependency is born: through incremental, individually sensible decisions. The 3 patterns that create them 1. Barrel files ( index.ts re-exports) Barrel files are the biggest source of accidental cycles in TypeScript projects. // features/user/index.ts — re-exports everything in the feature export { UserService } from ' ./user.service ' ; export { UserRepository } from ' ./user.repository ' ; export { UserController } from ' ./user.controller ' ; export { formatUser , validateUser } from ' ./user.utils ' ; Now every file in the user feature imports from ../user (the barrel) for cleaner paths. And any utility the barrel re-exports cannot safely import anything else from the barrel without creating a cycle. // user.utils.ts import { UserService } from ' ../user ' ; // ← imports the barrel // The barrel re-exports user.utils → user.utils imports the barrel → cycle Teams adopt barrel files for