Across 2,972 functions analyzed at commit e038e31, Kong/insomnia has 178 functions in the critical band — and every single hotspot in the top five sits in the ‘fire’ quadrant, meaning structurally complex and actively changing right now. The highest-priority function, clientAction in the project-update route, carries an activity-weighted risk score of 18.66 backed by a cyclomatic complexity of 63 and fan-out to 27 distinct callees, and it was modified 9 days ago. I would start there, then work through the Git sync and render pipeline functions that round out the top five — all of them changed in the same 9-day window.
The table below ranks functions by activity-weighted risk — a score that multiplies structural complexity by recent commit frequency. A function that is both hard to understand (high cyclomatic complexity) and actively changing is a higher priority than one that is complex but untouched. CC = cyclomatic complexity (independent execution paths); ND = max nesting depth; FO = fan-out (distinct callees).
Top 5 Hotspots
| Function | File | Risk | CC | ND | FO |
|---|---|---|---|---|---|
clientAction | packages/insomnia/src/routes/organization.$organizationId.project.$projectId.update.tsx | 18.7 | 63 | 6 | 27 |
collectMergeConflicts | packages/insomnia/src/sync/git/git-vcs.ts | 18.6 | 27 | 8 | 15 |
getInsomniaV5DataExport | packages/insomnia/src/common/insomnia-v5.ts | 18.3 | 26 | 6 | 49 |
next | packages/insomnia/src/common/render.ts | 17.7 | 36 | 6 | 11 |
render | packages/insomnia/src/common/render.ts | 16.9 | 20 | 6 | 13 |
Large Repo Analysis
insomnia is a large repository. To stay within memory constraints, this analysis used hybrid touch mode: structural complexity — CC, ND, FO — is measured precisely for every function. Git activity is tracked at the function level (via git log -L) only for files with 5 or more commits in the last 30 days; other files use a file-level approximation. Rankings therefore surface functions that are both structurally complex and in the most actively-changing parts of the codebase. Dormant code with high structural complexity will rank lower than it would under a full per-function analysis — to surface it, run hotspots analyze . --per-function-touches on a machine with sufficient memory.
Risk distribution
2,972 functions analyzed
The quadrant picture is stark: 568 functions are in the ‘fire’ quadrant — structurally complex and recently active — and zero functions sit in the ‘debt’ quadrant. That means there is no dormant complexity to schedule for a future sprint; the structural risk in this repo is live. The remaining 2,404 functions are in ‘watch’ (low complexity, active), which reflects a healthy baseline for the majority of the codebase.
High cyclomatic complexity — many independent execution paths, each a potential bug surface and required test case.Deeply Nested×5Deeply Nested
Control structures nested 4+ levels deep, making it hard to reason about the full execution state at inner branches.Exit Heavy×5Exit Heavy
Multiple return or throw paths dispersed through the body — each exit needs separate test coverage.God Function×5God Function
Calls an unusually large number of distinct functions (high fan-out), making it the structural centre of gravity for a subsystem.Long Function×5Long Function
Function body is too long to review in a single pass; likely contains multiple distinct responsibilities.Cyclic Hub×1Cyclic Hub
Participates in a call cycle with other high-traffic functions, creating circular dependency risk.
Every one of the top five hotspots carries all five of the same antipattern flags: complex branching, deeply nested control flow, multiple exit paths, god-function coupling, and excessive length. That uniformity is a signal worth pausing on — these are not five unrelated problems, they are the same architectural pattern repeated across different subsystems.
Top 5 hotspots
clientAction — organization.$organizationId.project.$projectId.update.tsx
Based on its name and file path, clientAction is the Remix action handler for the project-update route — the function that processes form submissions or API mutations when a user updates a project within an organization context. That role alone suggests it must validate inputs, handle authorization checks, coordinate persistence, and return appropriate responses, which likely explains its shape.
The cyclomatic complexity of 63 is the single most alarming number in this analysis.
At CC 63, there are at minimum 63 independent execution paths through this function. In TypeScript specifically, that number understates the true branch surface — type narrowing inside conditional blocks adds implicit forks that cyclomatic complexity does not count. Each of those 63 paths is a required test case for full coverage, and the fan-out of 27 means changes here can propagate to 27 downstream callees. Combined with a nesting depth of 6, reasoning about which branch is executing at any given point requires holding a substantial mental model simultaneously.
The exit-heavy pattern compounds the test-coverage problem: multiple early return paths mean that a test reaching line N tells you nothing about what happens at line N+1. The god-function pattern confirms that this handler is doing far more than routing logic should — side effects, error handling, and business rules appear to be co-located rather than delegated.
This function was last touched 9 days ago and has 1 commit in the last 30 days. The file has a single author in the last 90 days and no bug-linked commits or reverts on record, so there is no historical defect signal to amplify the urgency — but the structural complexity at this activity level is enough on its own.
Recommendation: Apply extract-method refactoring to break clientAction into a validation phase, an authorization phase, and a persistence phase — each as a named, independently testable function. The goal is to bring the residual CC of the orchestrating function below 10, leaving complexity only in the extracted helpers where it can be tested in isolation.
collectMergeConflicts — git-vcs.ts
collectMergeConflicts sits inside the Git VCS synchronization layer and, from its name, is responsible for identifying and aggregating merge conflicts during a sync operation. Conflict detection is inherently branchy work — every file comparison is a conditional, and multi-way merge semantics multiply the cases — so some complexity here is expected. The question is whether the current shape is manageable.
The nesting depth of 8 is the metric I find most concerning here.
At ND 8, the innermost logic is eight levels deep inside control structures. That is well past the threshold of 4 where reasoning becomes difficult, and firmly into territory where a reader must track the combined preconditions of eight nested branches to understand what a single line does. In TypeScript, async/await chains can add further implicit nesting that the ND metric does not fully capture.
With CC 27, there are 27 independent paths through the conflict collection logic, and fan-out of 15 means this function coordinates with 15 other callees — likely file-tree traversal utilities, diff parsers, and conflict formatters. Changes to any of those 15 functions carry a non-trivial probability of affecting behavior here. Like the other top hotspots, this function carries the exit-heavy and long-function patterns, meaning partial execution paths are abundant and the function is not easily skimmed.
The file has a single author in the last 90 days and was last touched 9 days ago with 1 commit in the 30-day window. No bug-linked commits or reverts are recorded, so the history is clean — but ND 8 in active sync code is a structural risk that does not need a bug history to justify attention.
Recommendation: Identify the innermost nested blocks — likely the per-file or per-hunk comparison loops — and extract them into dedicated functions with names that describe what conflict condition they detect. Reducing ND from 8 to 4 or below will also mechanically reduce CC as the branches are redistributed.
getInsomniaV5DataExport — insomnia-v5.ts
The name getInsomniaV5DataExport and the insomnia-v5.ts filename together suggest this function assembles the full V5 export payload — serializing workspaces, requests, environments, and related entities into the versioned export format. The v5 suffix in both the function name and the file is worth noting: this implies a versioned or generational API, which often means it was introduced to supersede an earlier export format and may still be evolving.
The fan-out of 49 is the defining metric here — the highest in the top five by a wide margin.
Fan-out of 49 means this function directly calls 49 distinct functions. That is effectively a dependency on nearly every entity serialization utility in the codebase. Any change to any one of those 49 callees — a type signature update, a renamed field, a changed default — can silently alter the shape of the export without this function’s own logic changing at all. This makes getInsomniaV5DataExport one of the highest blast-radius functions in the repository even though its own CC of 26 is lower than clientAction’s.
With ND 6 and the god-function pattern confirmed, the function is also doing aggregation, conditional filtering, and format negotiation inline rather than delegating to purpose-built serializers. Combined with the exit-heavy pattern, testing every valid export shape requires navigating a matrix of path combinations.
Recommendation: Introduce a dedicated serializer per entity type (requests, environments, authentication configs, etc.) and have getInsomniaV5DataExport act as a thin orchestrator that calls them in sequence. This reduces fan-out at the top level, makes each serializer independently testable, and limits the blast radius of any single entity schema change.
next — render.ts
next in render.ts is notable for carrying the cyclic_hub pattern — the only function in the top ten to do so. In a render pipeline context, a function named next is likely a recursive or iterative step that advances a templating or rendering pass: process the current node, then invoke the next step. The cyclic-hub pattern means this function both calls into and is called from other functions in a cycle, creating a tight dependency loop that makes it hard to reason about independently.
CC 36 means 36 independent paths through the rendering step logic.
In a TypeScript templating engine, those 36 paths likely correspond to handling different template tag types, escape sequences, encoding variants, and error conditions — each a separate branch. Because next is a hub in a dependency cycle, changes here have a compounding effect: they simultaneously affect callers and callees, making safe refactoring harder than for a simple leaf function. The exit-heavy pattern adds to this — multiple early returns scattered through 36 paths mean the function’s postconditions are difficult to state concisely.
next shares render.ts with the fifth hotspot render, and both were touched 9 days ago. The file has a single author in the last 90 days and no historical defect signals.
Recommendation: Before touching next, map the cycle: identify which functions call next and which next calls back into, then look for a way to introduce an explicit state machine or accumulator that removes the cyclic dependency. Breaking the cycle is a prerequisite for safely reducing CC, because extracting sub-functions while the cycle exists just moves the coupling without eliminating it.
render — render.ts
render is the public-facing entry point of the same render pipeline as next. From the file path and function name, it likely accepts a template string and a context object, then initiates the recursive rendering process — delegating to next and other helpers for the actual traversal. That means render is the function external callers reach for, while next is the internal workhorse.
With CC 20 and ND 6, render is independently complex enough to warrant attention even without the cyclic_hub flag its neighbor carries. Fan-out of 13 covers a meaningful portion of the render utility surface, and the same five antipattern flags apply.
The fact that both render and next appear in the top five and were changed together 9 days ago suggests they were modified as a unit — which is consistent with a shared architectural issue rather than two separate problems. Addressing the cyclic coupling in next will almost certainly require coordinated changes to render at the same time.
Recommendation: Treat render and next as a single refactoring unit. Define a clear contract between the public render entry point and the internal next step — ideally as explicit TypeScript types for the render context and the intermediate state — before splitting any logic out. Establishing that contract first will prevent the extract-method refactoring from simply redistributing the confusion.
What the patterns tell us collectively
All five top hotspots share the same five antipattern flags. That is not a coincidence — it reflects a consistent design preference across multiple subsystems for consolidating logic into large, multi-exit functions rather than decomposing it into smaller, single-purpose ones. The exit-heavy pattern in particular is worth calling out: when a function has many early returns, each return is an implicit contract that callers may be relying on, which makes the function harder to refactor safely. Extracting sub-functions from an exit-heavy function requires first understanding which callers depend on which exit path, and that analysis is non-trivial at CC 20–63.
The good news is that the watch-quadrant functions further down the list — decodeEncoding, resolvePath, buildRequestName, and getBundlePluginMap — are all low complexity with no structural antipatterns flagged. They bear monitoring given their recent activity (2–3 commits in 30 days across multiple authors), but they are not refactoring priorities.
Patterns Found
Antipatterns detected across the top functions in this snapshot:
| Pattern | Occurrences |
|---|---|
complex_branching | 5 |
deeply_nested | 5 |
exit_heavy | 5 |
god_function | 5 |
long_function | 5 |
cyclic_hub | 1 |
These labels belong to two tiers — Tier 1 (structural): complex_branching, deeply_nested, exit_heavy, long_function, god_function. Tier 2 (relational/temporal): hub_function, cyclic_hub, middle_man, neighbor_risk, stale_complex, churn_magnet, shotgun_target, volatile_god.
Reproduce This Analysis
git clone https://github.com/Kong/insomnia
cd insomnia
git checkout e038e317f7870c11b0dd0f2c972944e9dc6a84ed
hotspots analyze . --mode snapshot --explain-patterns --force --hybrid-touches 5
To run the same analysis on your own codebase, run hotspots analyze . --mode snapshot in any local git repo — no configuration required.
I use Hotspots to highlight structural and activity risk — not “bad code.” I treat these findings as a prioritization aid, not a bug predictor. Editorial policy →