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
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: 1Moderate 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: 7High 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 functionsInterpreting Values
| Average Score | Assessment | Action |
|---|---|---|
| ≤ 5 | Well-maintained | Keep monitoring for upward trends |
| 6 - 10 | Moderate — typical for established codebases | Focus on high-complexity functions in new code |
| 11 - 20 | High — significant maintenance burden | Plan targeted refactoring sprints |
| > 20 | Critical — high bug risk | Prioritize 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