NxtSoftLabs
← All writing

Impact analysis in ~10ms: everything a change touches

July 12, 2026·5 min read

To find everything a code change touches, CGraph walks the transitive blast radius of a node in its resolved graph and returns the answer in a single query — a warm-query round-trip measured at a 10.6ms median in our benchmark. No multi-round grep trace, no reading each caller's callers by hand. You ask "what breaks if I change this?" and get a direction-aware, depth-ranked answer back.

This is the query most agents skip, because doing it by hand is tedious. Here is how CGraph makes it a one-liner.

The query, not the manual trace

"Find all usages" is easy to say and painful to do properly. Grep for a symbol and you get its direct references. But the real question — what is the transitive blast radius if I change this function's signature? — means finding the callers, then the callers of those callers, and so on, filtering out the textual matches that aren't actually call sites. By hand that's a multi-round trace, and it's exactly the kind of tedious work a coding agent tends to short-circuit.

CGraph turns it into one operation. Per the retrieval docs, the daemon exposes an impact operation defined as "the transitive blast radius of a change." Because the graph model already encodes calls as directed edges, impact is just a traversal — walk outward along the dependency edges from the node you're about to touch, ranked by depth, and return what you reach.

cgraph-client --root /path/to/project impact '{"q":"parseConfig"}'

The response is JSON: the set of nodes reachable from the change, each with its file:line, so an agent gets structured locations rather than a wall of source to re-read.

Why it's fast: the graph is already warm

The "~10ms" only makes sense once you know where the graph lives. CGraph doesn't parse anything at query time. The daemon, graphd, builds the graph once on startup and then holds it resident in memory, serving operations over a local socket. A query is a single round-trip into RAM — no disk read, no re-scan, no re-parse.

That's the architectural difference the benchmark isolates. In our comparison against Graphify, the warm-query round-trip was a 10.6ms median (over 20 runs) versus 167ms for a tool with no daemon that reloads its graph from disk on every query — a 15.8x gap that's about architecture, not just language. Keep the graph warm and impact analysis is interactive; rebuild it every time and it isn't.

CGraph — resident daemon, query hits RAM10.6 ms
no daemon — graph reloaded from disk per query167 ms
Warm-query round-trip, median of 20 runs. Self-run benchmark on CGraph's own repo in a Debug build — caveats in the benchmark post.

The daemon also stays current on its own. While watching the tree, it folds ordinary edits into the graph within a couple of seconds, and a large batch like a branch switch collapses into one full rescan by design. So the impact answer reflects the code as it is now, not as it was at the last manual rebuild — with the honest caveat that freshness lags an edit by the watch cadence plus debounce, a few seconds.

Read the ~10ms carefully

One number, quoted precisely. The 10.6ms figure is a warm-query round-trip median, and it comes with caveats we published alongside it:

  • It's a self-run benchmark: CGraph, measured by its authors, on CGraph's own repository (141 source files, a graph of ~960 nodes).
  • It was run against a Debug build — unoptimized — so the native number is, if anything, conservative.
  • It's a round-trip measurement, not a headline for every query type on every repo. Your latency depends on your graph size and the traversal depth.

Treat it as "impact analysis is interactive on a warm daemon," not as a guaranteed constant. The mechanism — traverse a resident, resolved graph instead of re-deriving structure from text — is what generalizes; the exact millisecond count is one measurement on one repo. CGraph's own performance docs deliberately publish mechanics rather than latency claims for this reason.

What blast radius saves an agent

The speed matters, but the token cost is what hits an agent's bill. In the benchmark's transitive-blast-radius task, CGraph answered in 216 tokens and one call; the grep equivalent was a multi-round manual trace of hundreds to thousands of tokens — the exact task agents most often skip. So the practical comparison, as we put it there, "is often 216 tokens versus the analysis never got done."

That's the real win. It's not that impact analysis is 15x faster than some other tool. It's that a direction-aware, depth-ranked blast radius exists as a single query at all, instead of being a tedious trace an agent decides not to run before it edits a shared function.

Impact is one of several graph operations

impact sits alongside the other operations the daemon exposes through the same handler: query (find nodes), explain (a node and its role), path (the shortest path between two symbols), and context (a token-budgeted neighborhood packed for an agent). They share one graph and one code path, so an agent and a shell get identical semantics.

The graph they all read is the deterministic one CGraph builds by parsing your source — the extraction that produces those call edges is covered in How CGraph extracts a code graph across 11 languages.

Try it

Start the daemon against a checkout, then ask what a change touches:

graphd --root /path/to/project
cgraph-client --root /path/to/project impact '{"q":"YourSymbol"}'

The daemon, the client, and the impact traversal are open source — read the code on GitHub. And if you want the full methodology behind the 10.6ms figure and the token comparisons, it's all in the CGraph benchmark post, scripts included.