Introducing tdepend - Architectural Fitness for TypeScript

Mohamed Saad

Large TypeScript codebases inevitably accumulate architectural debt. As teams grow and features are added, dependencies become tangled, circular references emerge, and the overall structure becomes increasingly difficult to maintain and understand.

tdepend is a JDepend-inspired dependency analysis tool designed specifically for the TypeScript ecosystem. Available as both a CLI tool and a programmatic library, it helps you monitor and maintain architectural health through automated metrics and quality gates.

Why Architectural Analysis Matters

As your TypeScript project grows, several critical issues commonly emerge:

  • Tight Coupling: Modules become overly interdependent, making changes risky
  • Circular Dependencies: Components reference each other in cycles, creating fragile designs
  • Poor Abstraction: Code becomes concrete and difficult to extend
  • Hidden Complexity: Dependencies are invisible until they cause problems

Traditional code reviews and linting tools catch syntax and style issues but often miss these deeper architectural problems that impact long-term maintainability.

What tdepend Provides

tdepend offers comprehensive architectural metrics inspired by Robert C. Martin’s work on software architecture:

Core Architectural Metrics

  • Ca (Afferent Coupling): How many modules depend on this module
  • Ce (Efferent Coupling): How many modules this module depends on
  • Abstractness: Ratio of abstract classes/interfaces to concrete implementations
  • Instability: Measure of how likely a module is to change
  • Distance: How far a module is from the ideal main sequence

Circular Dependency Detection

tdepend automatically detects and reports circular dependencies in your codebase, helping you identify architectural violations that can lead to build issues and tight coupling.

Quality Gates for CI/CD

Built-in threshold checking allows you to fail builds when architectural metrics exceed acceptable limits, preventing architectural degradation over time.

Getting Started

Installation is straightforward:

# Install globally
npm install -g tdepend

# Or with your preferred package manager
pnpm add -g tdepend
yarn global add tdepend

Run your first analysis:

# Analyze your TypeScript project
tdepend analyze

# Use a custom configuration
tdepend analyze --config my-config.json

# CI mode with JSON output
tdepend analyze --ci

Configuration

tdepend is fully configurable through a tdepend.config.json file:

{
  "rootDir": "src",
  "include": ["src/**/*.ts", "src/**/*.tsx"],
  "exclude": ["**/*.test.ts", "**/*.spec.ts", "dist"],
  "metrics": {
    "enabled": ["coupling", "abstractness", "distance", "cycles"],
    "thresholds": {
      "distance": 0.6
    }
  },
  "analysis": {
    "target": null,
    "value": null
  },
  "ci": {
    "failOnThreshold": true,
    "failOnCycle": false,
    "outputFormat": "json"
  }
}

Key Configuration Options

  • Selective Analysis: Choose which metrics to compute (coupling, abstractness, distance, cycles)
  • Scoped Analysis: Focus on specific modules, classes, or namespaces
  • Flexible Thresholds: Set custom limits for distance from main sequence
  • CI Integration: JSON output and configurable failure conditions

Integrating with CI/CD

Add architectural checks to your continuous integration pipeline:

# .github/workflows/architecture.yml
name: Architecture Check
on: [pull_request]
jobs:
  analyze:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - run: npm install -g tdepend
      - run: tdepend analyze --ci

The --ci flag provides JSON output and will exit with code 1 if thresholds are exceeded, making it perfect for automated quality gates.

Advanced Features

Targeted Analysis

Analyze specific parts of your codebase:

# Analyze a specific module
tdepend analyze --target module --value UserService

# Analyze a specific class
tdepend analyze --target class --value PaymentProcessor

Zero Runtime Dependencies

tdepend is designed with zero runtime dependencies for analysis, ensuring it won’t interfere with your project’s dependency tree or introduce security vulnerabilities.

Multiple Output Formats

Switch between human-readable console output for development and structured JSON for automation and tooling integration.

Programmatic API (v0.2.0+)

tdepend now works as both a CLI tool and an importable library, enabling deeper integration into your development workflows:

import { analyze, exportToFile } from 'tdepend';

// Run analysis programmatically
const result = await analyze({
  rootDir: 'src',
  include: ['src/**/*.ts'],
  failOnCycle: true
});

// Access detailed metrics
console.log(`Modules: ${result.modules.length}`);
console.log(`Cycles: ${result.cycles.length}`);

// Export complete analysis
await exportToFile(result, 'architecture.json');

Export & Integration

Export comprehensive analysis results with the --export flag:

tdepend analyze --export architecture-snapshot.json

The exported JSON includes:

  • Complete dependency graph (with proper serialization)
  • All computed metrics (Ca, Ce, A, I, D)
  • Normalized cycles with unique IDs
  • Configuration and violations

This makes it easy to:

  • Integrate with ts-arch or dependency-cruiser
  • Build custom dashboards and visualizations
  • Track architectural trends over time
  • Create automated refactoring tools

Integration with Architectural Tools

tdepend is designed to complement existing architectural tools:

With ts-arch:

import { analyze } from 'tdepend';

// Use tdepend's dependency graph for ts-arch rules
const result = await analyze({ rootDir: 'src' });
const dependencies = result.modules.map(m => ({
  file: m.filePath,
  imports: m.imports,
}));

// Apply ts-arch architectural rules using tdepend data

With dependency-cruiser: Export tdepend’s analysis for cross-validation with dependency-cruiser’s rules, ensuring comprehensive architectural governance.

With Custom Dashboards:

// Track architectural metrics over time
const dashboard = {
  timestamp: new Date().toISOString(),
  avgDistance: result.metrics.reduce((sum, m) =>
    sum + m.distance, 0) / result.metrics.length,
  topCoupled: result.metrics
    .sort((a, b) => (b.Ce + b.Ca) - (a.Ce + a.Ca))
    .slice(0, 10)
};

// Send to your monitoring system
await sendToDashboard(dashboard);

This approach gives you metrics-based analysis from tdepend combined with rule-based enforcement from ts-arch – the best of both worlds for maintaining clean architecture.

Conclusion

Architectural health is crucial for long-term project success. tdepend brings proven dependency analysis techniques from the Java ecosystem to TypeScript, providing you with the tools needed to maintain clean, sustainable architecture as your codebase grows.

Start monitoring your TypeScript architecture today and catch architectural issues before they become technical debt.


Resources: