Skip to main content

Core analyzer

Cognitive Complexity

SonarSource's cognitive complexity metric — penalizes deeply nested control flow more than cyclomatic complexity does.

technical-debt core-cognitive

Cognitive Complexity

SonarSource's cognitive complexity metric — penalizes deeply nested control flow more than cyclomatic complexity does.

Cognitive complexity, introduced by SonarSource, addresses cyclomatic complexity's main shortcoming: it treats all branches as equally costly. In reality, a flat switch with 10 cases is easier to read than a triply-nested if ladder with the same number of branches.

The metric adds 1 for each control-flow statement (if, for, while, switch, catch) and applies a nesting penalty that grows with depth. Logical operator chains and break-with-label statements also contribute. The result correlates more closely with how developers actually rate code readability than cyclomatic complexity does.

Severity guide

info
Complexity is within excellent or good range. No action required.
warning
Complexity exceeds warning threshold or nesting depth exceeds 3. Refactoring is recommended to keep the file readable as it grows.
critical
Complexity exceeds critical threshold. Most developers will struggle to read this file without extensive study.

Examples

Before

function process(items) {
  if (items) {
    if (items.length > 0) {
      for (const item of items) {
        if (item.active) {
          if (item.type === 'a') {
            // do work
          }
        }
      }
    }
  }
}

After

function process(items) {
  if (!items || items.length === 0) return;
  for (const item of items) {
    if (!item.active || item.type !== 'a') continue;
    doWork(item);
  }
}

Guard clauses (early returns and `continue` statements) flatten the nesting hierarchy without changing behavior. Cognitive complexity drops from 9 to 3.

Remediation

Reduce nesting via guard clauses and early returns; extract deeply nested blocks into named helpers.

  • Identify the deepest nesting point and rewrite the outer condition to return or continue early instead of nesting the happy path.
  • Extract the body of any deeply nested loop or conditional into a named function — the function name documents the intent, and the call site loses an indent level.
  • Break long boolean chains (x && y && z && (a || b)) into named predicates that read like sentences.
  • Avoid nesting try/catch blocks unless the inner catch handles something meaningfully different from the outer one.

References

Documentation