NgFlow — Angular Reactive Flow Visualizer
A VS Code extension that turns an Angular component into a live, interactive dependency
graph — signals, computed()/effect() chains, and now the component's structural shape
(properties, methods, @Input()/@Output(), injected services) too, 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). It also has structural nodes (an @Input(), an
@Output(), a plain property, and a method) not pictured above.
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 — and
for the many components that don't use signals at all yet, it shows the component's shape
(properties, methods, inputs/outputs, injected services) instead of nothing.
Status
v0.1 — signals, plus a structural component graph. signal()/computed()/effect()
chains are fully supported, and so is a structural graph (properties, methods,
@Input()/@Output(), injected services) for files with few or no signals. RxJS observable
chains, template-binding resolution from a paired .html file, 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.
- Structural component graph for everything else — plain properties, methods,
@Input()/@Output() (or signal-based input()/output()/model()), and injected
services — shown alongside any signals, or on its own for files with none. Toggle off with
ngflow.showStructuralMembers: false to see only the reactive graph.
- 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 |
| Property |
a plain (non-signal) class field |
muted rectangle |
| Method |
a method, getter/setter, constructor, or arrow-function class field |
muted triangle |
| Input |
@Input() or signal-based input() |
muted parallelogram, blue accent |
| Output |
@Output() or signal-based output() |
muted tag shape, orange accent |
| Model |
signal-based model() (two-way) |
muted chevron, purple accent |
| Service |
a dependency from inject() or a constructor parameter property |
muted rounded rectangle |
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 an Angular component's
.ts file — with or without signals; a plain, signal-free
component shows a structural graph of its properties/methods/inputs/outputs/services.
- 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. |
ngflow.showStructuralMembers |
true |
Show properties/methods/inputs/outputs/services alongside (or instead of) the reactive graph. Set to false for a reactive-only graph. |
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.
| |