NgFlow — Angular Reactive Flow Visualizer
A VS Code extension that turns an Angular component's signal() / computed() / effect()
declarations into a live, interactive dependency graph — right next to the code, updated as
you save.

The screenshot above is samples/counter.component.ts — a
fixture that deliberately exercises every edge case NgFlow handles in one file (see
What it detects below).
Why
Angular's reactive primitives create dependency chains that are easy to lose track of once a
component grows: which signals actually feed a given computed()? Does this effect()
quietly write back to something it also reads? Is that signal even used anywhere? NgFlow
answers those questions visually instead of by tracing calls through the file by hand.
Status
v0.1 — signals only. computed() and effect() chains are fully supported; RxJS
observable chains, template-binding resolution, and cross-component graphs are later
milestones (not yet built — see DEVELOPMENT.md for the full requirements
doc's milestone plan).
Features
- Automatic detection of
signal(), computed(), and effect() declarations in the
active .ts file, with statically-resolved read/write relationships between them.
- Interactive graph in a VS Code Webview: distinct shape + color per node kind,
directional edges for reads/writes, pan/zoom, and a "fit to view" reset.
- Click a node → jump to its declaration in the editor.
- Re-parses on save by default (configurable), with a manual refresh command as a
fallback.
- Copy the graph as JSON — a flattened, agent-friendly export of the same graph, for
pasting into an AI chat as context. Available as a toolbar button and as a command.
- Never crashes on a syntax error. Mid-edit invalid syntax keeps showing the last valid
graph with a "stale" banner instead of throwing.
- Node cap with graceful fallback. Past a configurable node count, the panel shows a
textual summary instead of an unreadable/frozen graph.
- Fully offline. No network calls, no telemetry, no cloud dependency — works the same in
local, Remote SSH, WSL, and Codespaces contexts.
What it detects
| Node kind |
Meaning |
Shape |
| Signal |
a signal() declaration |
filled circle |
| Computed |
a computed() declaration |
filled diamond |
| Effect |
an effect() declaration |
filled hexagon |
| External |
a signal/member reached through an inject()-provided service (this.auth.isLoggedIn()) |
dashed outline rectangle |
| Unresolved |
a dynamic/indirect reference NgFlow can't statically resolve, e.g. this[someVar]() or arr[i]() |
dotted amber tag |
And beyond plain detection, it also flags:
- Dead signals — declared but never read anywhere in the file (dimmed, dashed border).
- Conditional reads — a
computed()/effect() reading a dependency only inside an
if/ternary branch (dashed edge). The dependency is still included, since it's a
best-effort static read, not a runtime guarantee.
- Cycles — an
effect() that writes to a signal it also reads (thick red border/edge
plus a red glow), so a feedback loop is obvious at a glance instead of hiding in the code.
See the requirements doc referenced in DEVELOPMENT.md for the complete list
of edge cases (§5.1/§5.3) and how each is handled.
Usage
- Open a
.ts file that uses Angular signals.
- Run NgFlow: Show Reactive Flow Graph from the Command Palette, or click the graph
icon in the editor title bar.
- Save the file to re-parse and re-render automatically, or run NgFlow: Refresh Graph
manually.
- Click any node to jump to its declaration. Use Copy as JSON to grab a compact
representation of the graph for an AI chat.
Settings
| Setting |
Default |
Description |
ngflow.maxNodes |
150 |
Node cap before falling back to a textual summary. |
ngflow.refreshMode |
on-save |
on-save re-parses automatically on file save; manual-only requires the Refresh command/button. |
Requirements
- VS Code 1.85+
- Angular 16–20 (signals stabilized in v17; partial support for experimental v16 signals)
Development
See DEVELOPMENT.md for architecture, how to run the extension via F5, run
tests, and package a .vsix.
License
See LICENSE.