Sitemap

Circular Dependency in Node.js

2 min readMay 31, 2025

--

Press enter or click to view image in full size

Currently I am working on some project in Node.js. Everything was going well. Suddenly, I started getting this frustrating error:

TypeError: generateTransactionRefNumber is not a function

At first, I thought it was a typo or a wrong import. But after double-checking everything, the issue persisted.

What Was Happening?

I had a service-based architecture with two key files:

  1. UtilityService.js– Handles common utility functions.
  2. TransactionService.js– Manages transaction-related logic.

Both services depended on each other.

  • UtilityServiceneeded a method from.TransactionService
  • TransactionService needed a method from.UtilityService

This created a circular dependency, meaning Node.js couldn’t fully load one module before the other.

How I Debugged It

  1. Used madge to Detect Circular Dependencies
npx madge --circular ./

And got this output:

✖ Found 1 circular dependencies!
...
1) services/UtilityService.js > services/TransactionService.js

2. Identified the issue,

  • UtilityService was importing TransactionService
  • TransactionService was importingUtilityService

This meant that when Node.js tried to load them, one of them was partially loaded, leading to undefinederrors (yeah, it says undefined 😏).

The Solution: Extract Shared Logic

Instead of having the two services depend on each other, I

  1. Created a New Helper File (TransactionHelper.js)
  • Moved shared functions (like⁣generateTransactionRefNumber) into this file.

2. Updated Imports

  • Both services now import TransactionHelper instead of each other

Before (Circular Dependency)

// UtilityService.js
const TransactionService = require("./TransactionService"); // Bad
// TransactionService.js
const UtilityService = require("./UtilityService"); // Bad

After

// UtilityService.js
const TransactionHelper = require("./TransactionHelper"); // good and right way

// TransactionService.js
const TransactionHelper = require("./TransactionHelper"); // good and right way

Why This Works

  • No More Circular Chain:
  • UtilityService → TransactionHelper
  • TransactionService → TransactionHelper
  • No Partial Loading: All dependencies resolve correctly.

Recommendation

  1. Avoid Mutual Imports: Services shouldn’t depend on each other directly.
  2. Use Helper Files: Extract shared logic to break circular dependencies.
  3. Check with madge: Detect circular dependencies early

Hope it will help you.
check out other articles

Get Ermiyas Damte’s stories in your inbox

Join Medium for free to get updates from this writer.

https://medium.com/@iamermi/how-to-document-your-node-js-rest-api-without-swagger-using-apidoc-f90c4a351c1b

--

--

Ermiyas Damte
Ermiyas Damte

Written by Ermiyas Damte

Developer | Software engineer