Average Complexity

complexity_avg — Mean cognitive complexity across all functions

What It Measures

complexity_avg is the arithmetic mean of cognitive complexity scores across all functions, methods, and classes in your repository. Each function gets a complexity score based on its nesting depth, number of branches, logical operators, and control flow structures. The average tells you the general level of complexity across your entire codebase.

Cognitive complexity accounts for factors that make code hard for humans to understand: deeply nested blocks, multiple conditional branches, ternary operators, logical short-circuits, and callback chains.

Why It Matters

Trend Indicator

A rising average complexity means that new code being added is more complex than the existing baseline. This is the earliest signal that code quality is degrading — it shows up in the average before individual functions cross alert thresholds.

Onboarding Difficulty

The average complexity directly correlates with how long it takes a new developer to understand your codebase. Lower averages mean faster onboarding and fewer misunderstandings.

Bug Density

Research consistently shows that functions with higher complexity contain more defects. While individual hot spots matter most, the average reflects the overall defect likelihood of your codebase.

How It's Calculated

Calculation

complexity_avg = sum(all function scores) / count(functions)

Each function's complexity score is computed by the tree-sitter parser and accounts for:

  • Nesting depth — each level of nesting adds incremental complexity
  • Branches — if, else if, switch cases, ternary operators
  • Loops — for, while, do-while, forEach
  • Logical operators — &&, ||, ?? with short-circuit behavior
  • Exception handling — try/catch/finally blocks
  • Callbacks and closures — nested functions and arrow functions

Examples

Low Complexity (score: 1)

function validateAge(age: number): boolean {
  if (age < 18) {          // +1 (single branch)
    return false;
  }
  return true;
}
// Complexity: 1

Moderate Complexity (score: 7)

function processOrder(order: Order): Result {
  if (!order) {                    // +1
    throw new Error("No order");
  }
  if (order.items.length === 0) {  // +1
    return { status: "empty" };
  }

  let total = 0;
  for (const item of order.items) {  // +1
    if (item.quantity > 0) {          // +2 (nesting)
      total += item.price * item.quantity;
    }
  }

  if (total > 100 && order.isPremium) {  // +1, +1 (&&)
    total *= 0.9;
  }

  return { status: "processed", total };
}
// Complexity: 7

High Complexity (score: 18) — Needs Refactoring

function calculateShipping(order: Order): number {
  let cost = 0;
  if (order.country === "USA") {                    // +1
    if (order.state === "AK" || order.state === "HI") {  // +2, +1
      cost = 25;
    } else if (order.total > 100) {                 // +1
      cost = 0;
    } else {                                        // +1
      cost = 10;
    }
  } else if (order.country === "Canada") {          // +1
    cost = order.total > 150 ? 15 : 25;            // +2
  } else {                                          // +1
    for (const zone of SHIPPING_ZONES) {            // +2
      if (zone.countries.includes(order.country)) { // +3
        cost = zone.rate;
        break;
      }
    }
  }
  if (order.isPriority && cost > 0) {               // +1, +1
    cost *= 2;
  }
  if (order.hasInsurance) {                          // +1
    cost += 5;
  }
  return cost;
}
// Complexity: 18 — break into smaller functions

Interpreting Values

Average ScoreAssessmentAction
5Well-maintainedKeep monitoring for upward trends
6 - 10Moderate — typical for established codebasesFocus on high-complexity functions in new code
11 - 20High — significant maintenance burdenPlan targeted refactoring sprints
> 20Critical — high bug riskPrioritize decomposition of complex functions

Reducing Average Complexity

1. Use Early Returns (Guard Clauses)

Return early from functions when preconditions are not met. This eliminates nesting and makes the happy path clear.

// Before: complexity 3
function process(data) {
  if (data) {
    if (data.isValid) {
      return processItems(data.items);
    }
  }
}

// After: complexity 1
function process(data) {
  if (!data?.isValid) return;
  return processItems(data.items);
}

2. Extract Functions

Break complex logic into smaller, well-named functions. This distributes complexity and improves readability. The average goes down because each function carries less weight.

3. Replace Conditionals with Lookup Tables

Use objects or maps instead of chains of if/else or switch statements.

// Before: complexity 4
function getDiscount(type: string): number {
  if (type === "gold") return 0.2;
  else if (type === "silver") return 0.15;
  else if (type === "bronze") return 0.1;
  return 0;
}

// After: complexity 0
const DISCOUNTS: Record<string, number> = {
  gold: 0.2, silver: 0.15, bronze: 0.1
};
function getDiscount(type: string): number {
  return DISCOUNTS[type] ?? 0;
}

4. Use Array Methods Instead of Loops

Replace nested loops with filter, map, and reduce. These are declarative, avoid nesting, and are often more readable than imperative loop code.

Related Metrics

  • complexity_max — The single highest complexity score; useful for finding the worst offender
  • complexity_p95 — 95th percentile; better than max for alerting because it ignores single outliers
  • total_loc — Long functions tend to have higher complexity