# No circular dependencies

- **Pattern:** `ab-000664` (`code-maintainability.code-organization.no-circular-deps`)
- **Severity:** critical
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-000664
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-000664)

## Why it matters

Circular dependencies cause modules to receive `undefined` at initialization time because JavaScript resolves the cycle by partially evaluating one module before the other is ready. This produces runtime bugs that are invisible to the type system and nearly impossible to reproduce reliably. CWE-1120 (Excessive Complexity) applies: circular graphs make the build tool's evaluation order non-deterministic and prevent tree-shaking, silently bloating your bundle. AI-generated codebases are especially prone to cycles because utility files get written to "reach back up" into components they originally served.

## Severity rationale

Critical because circular imports can produce silent `undefined` values at runtime that bypass type checking and are extremely difficult to trace back to their root cause.

## Remediation

Find all cycles first, then break them by moving shared logic to a file that neither participant imports. Run:

```bash
npx madge --circular src/
# or
npx dpdm --circular src/
```

To break a cycle: extract the shared code into a new neutral module, or use dependency injection. Prevent future cycles by adding `eslint-plugin-import` with the `import/no-cycle` rule — it fails the lint check the moment a cycle is introduced.

## Detection

- **ID:** `no-circular-deps`
- **Severity:** `critical`
- **What to look for:** Scan import statements across source files for cycles. A circular dependency exists when Module A imports from Module B, which imports from Module C (or directly back to A), creating a loop. Look for these common patterns:
  - A `utils` file that imports from a component
  - A component that imports from a page, which imports from that component
  - A `types` file that imports runtime values
  - Barrel files (`index.ts`) that re-export and create unintended cycles

  Focus on `src/`, `app/`, `components/`, `lib/`, `hooks/` directories. If the project has a tool like `madge`, `dpdm`, or `eslint-plugin-import` with the `no-cycle` rule configured, note its presence. Otherwise, trace imports manually for the 10-20 largest/most central files.
- **Pass criteria:** Enumerate all import chains among the 10-20 most central files. No circular import chains detected in the source files examined. Barrel files do not create cycles. Report even on pass: "Examined X files, 0 circular import chains found."
- **Fail criteria:** One or more circular import chains are found in source files. Do not pass when a barrel file (`index.ts`) re-exports create an indirect cycle — trace through barrel re-exports.
- **Skip (N/A) when:** The project has only 1-3 source files with no meaningful import graph. Signal: fewer than 5 JavaScript/TypeScript source files.
- **Detail on fail:** Name the specific cycle found. Example: `"Circular dependency: components/UserCard.tsx → lib/auth.ts → components/UserCard.tsx"` or `"Barrel file src/components/index.ts creates cycle with components/Dashboard/index.ts"`
- **Remediation:** Circular dependencies can cause subtle runtime bugs (undefined values at initialization time), slow build tools, and make refactoring unpredictable. They're especially common in AI-generated codebases where utilities "reach back up" to components.

  To find all cycles, run:
  ```bash
  npx madge --circular src/
  # or
  npx dpdm --circular src/
  ```

  To fix a cycle, identify which import is creating the loop and break it by:
  1. Moving the shared logic to a new file that neither circular participant imports
  2. Using dependency injection instead of direct imports
  3. Restructuring barrel files to avoid re-export cycles

  Prevent future cycles by adding `eslint-plugin-import` with the `import/no-cycle` rule to your ESLint config.

## External references

- iso-25010 maintainability.modularity
- iso-25010 maintainability.analysability
- cwe CWE-1120

Taxons: code-quality

HTML version: https://auditbuffet.com/patterns/ab-000664
