Across 3,031 functions in TanStack/query, 84 have reached critical risk band — and the single highest activity-weighted risk score belongs to experimental_createQueryPersister in packages/query-persist-client-core/src/createPersister.ts, which carries a recent commit activity of 15.79. That score reflects recent, frequent commit activity against a function that already has a cyclomatic complexity of 14, nesting depth of 6, and fan-out of 27 — the combination means every change lands in structurally dense territory with wide coupling surface. The persistence subsystem and the devtools Explorer component dominate the top five hotspots, signaling that these two layers deserve immediate review attention.
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 |
|---|---|---|---|---|---|
experimental_createQueryPersister | packages/query-persist-client-core/src/createPersister.ts | 16.8 | 14 | 6 | 27 |
<anonymous> | packages/query-codemods/src/v5/remove-overloads/transformers/filter-aware-usage-transformer.cjs | 16.3 | 23 | 5 | 20 |
<anonymous> | packages/query-codemods/src/v5/remove-overloads/transformers/filter-aware-usage-transformer.cjs | 15.7 | 11 | 5 | 30 |
restoreQueries | packages/query-persist-client-core/src/createPersister.ts | 15.6 | 19 | 6 | 8 |
Explorer | packages/query-devtools/src/Explorer.tsx | 15.4 | 26 | 3 | 38 |
Codemod / Tooling Files in Results
Two of the top five hotspots are anonymous functions inside packages/query-codemods/src/v5/remove-overloads/transformers/filter-aware-usage-transformer.cjs. This is a codemod transformer — a migration tool that rewrites user code during the v5 upgrade path, not application runtime code. It scores highly because it contains dense AST-traversal branching (CC 23 and CC 11, ND 5 for both, fan-out of 20 and 30 respectively) and has seen recent commit activity (recent commit activity 15.42 and 14.76). These scores reflect legitimate tooling complexity, not production risk. To exclude codemod files from future hotspot runs, add "exclude": ["packages/query-codemods/**"] to your .hotspotsrc.json.
Hotspot Analysis
experimental_createQueryPersister — packages/query-persist-client-core/src/createPersister.ts
Based on its name and location, this function is the factory entry point for the client-side query persistence feature — the experimental_ prefix is a deliberate signal that this API is not yet stable and is under active iteration, which is confirmed by its recent commit activity of 15.79 (the highest in the repo). A cyclomatic complexity of 14 means at least 14 independent execution paths run through it, a nesting depth of 6 means reasoning about any single path requires tracking six levels of control flow simultaneously, and a fan-out of 27 means it calls 27 distinct functions — making it a god function whose blast radius spans a significant portion of the persistence package. The complex_branching, deeply_nested, and exit_heavy patterns all co-occur here: the exit-heavy classification alone means test coverage must account for multiple early-return paths, each of which could mask a regression when the function changes.
Recommendation: Before the next change lands, write characterization tests that exercise each of the major exit paths to lock in current behavior. Then extract the branching sub-concerns — likely persistence strategy selection, cache validation, and serialization — into named helper functions to reduce both the fan-out coupling and the nesting depth in the factory itself.
restoreQueries — packages/query-persist-client-core/src/createPersister.ts
Living in the same file as experimental_createQueryPersister, restoreQueries likely handles rehydrating persisted query state back into the query client on startup or reconnect. Its cyclomatic complexity of 19 and nesting depth of 6 are both higher than its sibling function’s, suggesting the rehydration logic contains more conditional branching — possibly handling stale-data checks, version mismatches, or partial cache states — and its recent commit activity of 14.52 confirms it is changing at nearly the same pace. The exit_heavy and complex_branching patterns reinforce that there are many paths through this function, each a distinct test obligation.
Recommendation: Map the 19 independent paths before touching this function — a coverage report scoped to restoreQueries will reveal which branches are currently untested and highest risk. Consider decomposing the function along the lines of validation, deserialization, and cache-insertion responsibilities.
Explorer — packages/query-devtools/src/Explorer.tsx
The Explorer component in the devtools package is the UI tree renderer that allows developers to inspect query cache state at runtime. Its cyclomatic complexity of 26 is the second highest among the named top hotspots, and its fan-out of 38 — the highest of any named function in the data — means it depends on 38 distinct callees, making it a hub function with an unusually wide blast radius. Notably its nesting depth is only 3, so the complexity is driven by breadth of branching rather than deep nesting, consistent with a component that must render many different data shapes and states. With a recent commit activity of 14.53 it is actively changing, meaning the devtools UI is a live regression surface despite being a secondary tool.
Recommendation: Audit the 38 callees to identify which rendering concerns can be extracted into standalone sub-components or hooks; reducing fan-out is the highest-leverage action here. The god_function and long_function patterns both indicate this component is doing too much in one place — splitting by data type or rendering context is a natural seam.
Patterns Found
Antipatterns detected across the top functions in this snapshot:
| Pattern | Occurrences |
|---|---|
exit_heavy | 5 |
complex_branching | 4 |
deeply_nested | 4 |
god_function | 4 |
long_function | 4 |
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.
Key Takeaways
experimental_createQueryPersisterhas a recent commit activity of 15.79 — the highest in the repo — against a function theexperimental_prefix already marks as unsettled. Any change here is a regression risk until characterization tests cover its exit-heavy branching paths.restoreQueriesin the same file has cyclomatic complexity 19 with nesting depth 6 and is changing at recent commit activity 14.52: decomposing it by responsibility (validation, deserialization, cache-insertion) will reduce both the bug surface and the per-change review burden.- The
Explorerdevtools component’s fan-out of 38 is the broadest coupling point among named hotspots — splitting it into focused sub-components by rendering concern will contain the blast radius of future devtools changes.
Reproduce This Analysis
git clone https://github.com/TanStack/query
cd query
git checkout 391db367b3e7adeff9a0dd647474d1575a31a787
hotspots analyze . --mode snapshot --explain-patterns --force
To run the same analysis on your own codebase, run hotspots analyze . --mode snapshot in any local git repo — no configuration required.
Hotspots highlights structural and activity risk — not “bad code.” Findings are a prioritization aid, not a bug predictor. Editorial policy →