Glossary · Code health

What is cognitive complexity?

Cognitive complexity is a metric for how hard a function is to understand, not how many paths it has. It adds 1 for each break in linear flow (if, loops, catch, a whole switch) plus an extra point for each level of nesting. G. Ann Campbell of SonarSource published it in 2017 to fix cyclomatic complexity's blind spots.

Last reviewed: November 2026

Also called Nested complexity, Understandability metric

How cognitive complexity is measured

SonarSource's rules reduce to three ideas:

  1. Ignore structure that makes code easier to read, such as extracting a function.
  2. Add 1 for each break in linear flow: if, else if, else, ternary, loops, catch, a switch (once, however many cases), goto, and each sequence of like boolean operators (a && b && c is +1, a && b || c is +2).
  3. Add the current nesting level to a flow-breaking structure that sits inside another one.

Take the same four checks written two ways:

def enable(user, flag):
    if user:                          # +1
        if user.is_active:            # +2 (nested 1 deep)
            if user.plan == "pro":    # +3
                if flag:              # +4
                    enable_feature()  # cognitive 10, cyclomatic 5

def enable(user, flag):
    if not user: return               # +1
    if not user.is_active: return     # +1
    if user.plan != "pro": return     # +1
    if not flag: return               # +1
    enable_feature()                  # cognitive 4, cyclomatic 5

Both have cyclomatic complexity 5, because both have four decisions. Cognitive complexity drops from 10 to 4 because the checks no longer nest. The reverse also happens: a switch with 12 flat cases scores 13 cyclomatic and 1 cognitive, because a reader scans cases, not traces them.

Why cognitive complexity matters

Reading cost, not path count, is what slows reviews and causes mistakes in edits. Cognitive complexity gives that cost a number, so a refactor like the guard-clause rewrite above shows up as a score change, not an opinion. It agrees with cyclomatic complexity less than you would expect, which is the point: a function high on both is the strongest refactoring candidate, and one high on only one tells you which kind of problem it is. Campbell's white paper is the reference for the rules. Treat the number as a readability tool, not a bug predictor.

How to measure cognitive complexity yourself

  • SonarQube, SonarCloud and SonarLint compute it natively; the default rule threshold is 15.
  • ESLint: the sonarjs/cognitive-complexity rule in eslint-plugin-sonarjs.
  • Go: gocognit (gocognit -over 15 .).
  • Python: flake8-cognitive-complexity adds a check to flake8, and complexipy reports it per function.
  • Rust: Clippy has a cognitive_complexity lint (in the nursery group, off by default).

SonarSource's own tools are the reference implementation, so pick them if you want the published numbers exactly. The others are ports and can differ on edge cases.

How repowise measures cognitive complexity

repowise's walker computes a SonarSource-style cognitive score for every function in the same pass as cyclomatic complexity: a weighted nesting cost, with else if arms charged a flat +1 without opening a level, and a switch or match charged once with its case arms adding nothing. The score is stored and shown in a finding's details.

Reading cost is judged through several signals, all read from the source:

  • nested_complexity flags maximum nesting depth of 4 or more (high at 5, critical at 7). This is depth, not the cognitive total. It is a scored detector.
  • complex_conditional flags boolean expressions with 3 or more operators; a flat chain of one operator is not flagged.
  • repeated_nesting flags several nested blocks side by side in one function (3 or more, with CCN 5 or more); it is listed, not scored.
  • complex_method uses cyclomatic complexity (9 or more) and reports the cognitive value next to it.

Files are then ranked with git history, so a deeply nested function in a file changed 19 times this quarter outranks the same function in a quiet one. See repowise health on the CLI, get_health over MCP, the code health feature page and the refactoring plans page, which proposes Extract Method for the first lift. All analysis is deterministic and uses no LLM. For the two metrics side by side, see nested vs cyclomatic complexity.

FREQUENTLY ASKED

Cognitive complexity: questions

What is the difference between cognitive and cyclomatic complexity?

Cyclomatic complexity counts independent paths and ignores layout, so it sizes the tests a function needs. Cognitive complexity counts how hard the code is to follow and charges more for nesting. A flat 12-case switch scores 13 cyclomatic and 1 cognitive; four nested ifs score 5 and 10.

What is a good cognitive complexity score?

SonarSource's default threshold is 15 per function: above it the rule raises an issue. Lower it on code that changes often. There is no universal good number, only a point where a reviewer stops being able to follow the function.

Who invented cognitive complexity?

G. Ann Campbell at SonarSource, in the white paper "Cognitive Complexity: A new way of measuring understandability" (2017, revised 2018). It was designed so that scores match how developers judge readability.

How do you reduce cognitive complexity?

Flatten nesting with guard clauses (return early on a failed precondition), extract each phase or inner block into a named function, and replace long if-else ladders on one value with a lookup table. Each cuts the nesting penalty.

See it on your own repository.

Index a repository free and read the result for your own code and history. Rolling it out to a team? We will walk you through it.