
Engineering6 min read1,389 words
What Is Cyclomatic Complexity?
Cyclomatic complexity, defined by Thomas McCabe in 1976, counts a function's independent paths: one plus its decision points. McCabe proposed a limit of 10.
Jishu Labs
(Updated: Oct 27, 2026)
Cyclomatic complexity is a count of the linearly independent paths through a piece of code. Thomas McCabe defined it in "A Complexity Measure", published in IEEE Transactions on Software Engineering in December 1976. In practice it is one plus the number of decision points in a function, and under McCabe's structured testing method it is also the number of tests that function needs.
How is cyclomatic complexity calculated?
Cyclomatic complexity is calculated from a function's control-flow graph as M = E − N + 2P, where E is the number of edges, N the number of nodes and P the number of connected components, which is 1 for a single function. The shortcut gives the same answer: start at 1 and add 1 for every binary decision.
NIST Special Publication 500-235, written by Arthur Watson and Thomas McCabe in 1996, sets out the counting rules. An if or while adds one. A short-circuit operator such as C's && adds one, because it decides whether the right-hand side runs at all; a fully evaluated boolean operator adds nothing. A multiway decision such as a switch adds one less than its number of branches.
function shippingCost(order) { // 1 the base path
if (order.items.length === 0) return 0; // +1 = 2
if (order.isDigital) return 0; // +1 = 3
let cost = BASE_RATE;
for (const item of order.items) { // +1 = 4
if (item.weightKg > 10) { // +1 = 5
cost += HEAVY_SURCHARGE;
}
}
if (order.express && order.inStock) { // +1 for if, +1 for && = 7
cost *= 2;
}
return cost;
}
// Cyclomatic complexity: 7Counted by hand, that function scores 7, so covering a basis set of its independent paths takes seven test cases. Tools can disagree on the same code, because they make different choices about boolean operators, switch cases, default parameters and optional chaining.
What is a good cyclomatic complexity score?
The classic target is a cyclomatic complexity of 10 or less per function. McCabe proposed 10, Sonar's guide uses the same figure, and NIST SP 500-235 says limits as high as 15 have been used successfully by teams with advantages such as experienced staff and a comprehensive test plan. Tool defaults are looser, up to 25.
| Source | Threshold or scale | Notes |
|---|---|---|
| McCabe, NIST SP 500-235 (1996) | 10, or up to 15 | Limits over 10 only for projects with several operational advantages, such as experienced staff and a comprehensive test plan |
| Sonar | 10 or lower per function | Describes 1-10 as simple and 11-20 as moderate; suggests team limits such as 10 or 15 |
| Radon (Python) | A 1-5, B 6-10, C 11-20, D 21-30, E 31-40, F 41+ | Ranks run from A, low risk, to F, very high risk: error-prone, unstable block |
| ESLint complexity rule (JavaScript) | Default maximum 20 | Classic McCabe count by default; a modified variant counts each switch as 1 |
| Microsoft CA1502 (.NET) | Default 25 | Not enabled by default in .NET 10; the threshold is configurable |
No single number is official. NIST itself calls the precise limit "somewhat controversial". Pick a number your codebase can meet today, then lower it over time.
What does cyclomatic complexity not measure?
Cyclomatic complexity measures branching, not how hard code is to understand. SonarSource's cognitive complexity paper shows two methods that both score 4: a switch that maps a number to a word, which reads at a glance, and a pair of nested loops with a labelled continue that sums prime numbers, which takes real effort to follow.
- Flat switches score high. Every case adds one, which is why ESLint offers a modified variant and Microsoft's CA1502 page names a method with a large switch as a candidate for exclusion.
- Nesting is invisible. Three if statements in a row and three nested inside each other get the same score, though the nested version is harder to hold in your head.
- Names, coupling and concurrency do not count. A straight-line function with a race condition scores 1.
- Targets get gamed. Gate merges on the number and people split functions to pass the check without making them any clearer.
What is the difference between cyclomatic and cognitive complexity?
Cognitive complexity, created by G. Ann Campbell at SonarSource, scores how hard a function is to understand rather than how many paths it has. It adds one for each break in linear flow, adds more for each level of nesting, counts a whole switch once and counts each sequence of the same boolean operator once.
| Cyclomatic complexity | Cognitive complexity | |
|---|---|---|
| Introduced by | Thomas McCabe, 1976 | G. Ann Campbell, SonarSource |
| Measures | Independent paths through a function | Effort needed to understand a function |
| A switch statement | Adds one per case | Adds one for the whole switch |
| Nesting | Ignored | Each level adds weight |
| Four-way switch (getWords) | 4 | 1 |
| Nested prime-sum loops (sumOfPrimes) | 4 | 7 |
| Best used for | Planning tests, spotting outliers | Code review and readability |
The two example rows come from the paper itself, which is at version 1.7, dated 29 August 2023. They show the trade-off clearly: both methods need four tests to cover their paths, but only one of them is hard to read.
Keep both numbers
Cyclomatic complexity answers how many tests a function needs. Cognitive complexity answers how hard it is to read.
NIST SP 500-235 warns that discounting switch statements makes the count too small to test every branch, so keep the classic count for test planning even if you prefer cognitive complexity in code review.
How should teams use cyclomatic complexity?
Use cyclomatic complexity as a report and a prompt for review, not as a hard gate. Track it per function, compare outliers against the rest of your own codebase, and combine it with change frequency: a complex function that changes every week is a far better refactoring target than a complex function nobody touches.
- Report it in CI and in pull requests, and fail builds only on extreme values the team agrees should never ship.
- Set a threshold your code meets today, then lower it; the ESLint and CA1502 thresholds are both configurable.
- Write one test per basis path for a high-scoring function before you refactor it, so the refactor has a safety net.
- Pair it with cognitive complexity where your tooling reports both.
High complexity is one of the classic code smells, and left alone it becomes technical debt. For what automated review tools catch beyond metrics, see the comparison of AI code review tools.
Sensei, from Jishu Labs, adds quality and complexity scores (on its Pro plan) to a plain-English explanation of the code. Sensei reviews and explains any codebase with AI — instant explanations, health scoring, security findings, and concrete fixes in seconds. Treat its scores as a review aid alongside the deterministic count your linter reports, not a replacement for it.
Frequently Asked Questions
What is a good cyclomatic complexity?
10 or less per function is the classic target, from McCabe's original recommendation, and Sonar's guide uses the same figure. NIST SP 500-235 allows up to 15 for teams with strong practices, and tool defaults run higher: ESLint warns above 20 and Microsoft's CA1502 above 25.
Is cyclomatic complexity the number of tests I need?
Under McCabe's structured testing method, yes: the number of tests required for a module equals its cyclomatic complexity, one per path in a basis set of independent paths. Passing those tests exercises every decision outcome independently, but it does not prove the code is correct.
Do && and || count toward cyclomatic complexity?
Yes, in languages where they short-circuit, such as C, Java and JavaScript, because each one decides whether the next operand is evaluated. NIST SP 500-235 counts each C && as one, and ESLint's complexity rule counts && and || as well.
Should I fail the build on high cyclomatic complexity?
Usually not at a low threshold. A hard gate encourages splitting functions to satisfy the number without making the code clearer. Report the score, review outliers and fail the build only on extreme values that your team agrees should never ship.
How do I reduce cyclomatic complexity?
Replace long if-else chains with lookup tables or polymorphism, return early instead of nesting, extract well-named functions for distinct decisions and keep validation in one place. Reduce it where that makes the code easier to follow; a lower number is not the goal on its own.
References
- Structured Testing: A Testing Methodology Using the Cyclomatic Complexity Metric (NIST SP 500-235) — NIST (Arthur H. Watson and Thomas J. McCabe)
- Cognitive Complexity: A new way of measuring understandability — SonarSource (G. Ann Campbell)
- Cyclomatic Complexity Guide — Sonar
- complexity — ESLint
- Using radon programmatically — Radon Documentation
- CA1502: Avoid excessive complexity — Microsoft Learn
About Jishu Labs
Jishu Labs is a software development company founded in 2016. We build custom software, AI/ML systems, and full-stack web and mobile applications for clients, and we make eight AI tools for software teams.




