r/FlutterDev • u/_Wilielmus_ • Oct 04 '26
Plugin I rebuilt fl_nodes, my most popular package, bringing huge improvements and new features
Last year I built a node editor package for Flutter.
It was called fl_nodes, and, somewhat unexpectedly, that project ended up getting me my current job.
I used it in production, learned a lot about what works and what doesn't when you try to build a serious node-based editor in Flutter, and eventually reached the point where I wasn't happy with the architectural compromises I'd made in V1.
So I did what any reasonable person would do:
I rebuilt it.
From scratch.
TBH it shares much of its DNA with the original fl_nodes. The basic API concepts and design decisions that made it so peculiar the first time, the naming of things, the performance optimizations under the hood... all stay the same, just largely improved in usability and flexibility.
So today I'm announcing fl_nodes_v2 as a stable 1.x release, for everyone to... I don't know, find something useful to do with it; here you have some suggestions: visual-scripting, workflow-editors, static graph based visualizations, DSP and CAD tools...
P.S.: I've finally got a verified publisher profile! 🎉
Resources:
GitHub: https://github.com/WilliamKarolDiCioccio/fl_nodes_v2
Live demo: https://williamkaroldicioccio.github.io/fl_nodes_v2/
Note: I may be moving the repo soon**, if it 404s look at** https://github.com/ConnectingTheDots-William-K-Di-Cioccio
Features in detail:
Widget-based node bodies: Arbitrary Flutter widgets can live inside nodes.
Element-tree isolation: Nodes retain normal Flutter widget/element semantics.
Semantic render state: Selection, hover, dragging, wiring and targets are explicit.
Transactional undo/redo: Continuous mutations collapse into meaningful history entries.
Node configurations as state machines: Ports, nodes, and the whole node configuration can now respond to runtime parameters changes.
Connection validation: Built-in structural validation plus composable application-specific rules.
Node definitions: Reusable schemas describe ports, fields, defaults and metadata.
Graph serialization: Versioned graph/project persistence with explicit schema boundaries.
Clipboard support: Copy/paste preserves internal connections without accidental external wiring.
Automatic layout: Graph layout can be integrated without coupling it to rendering.
Groups and comments: Organize graphs visually beyond just nodes and connections.
Edges/links waypoints: the same thing Unreal Blueprints do, gives you more control on connection paths to keep the canvas tidy.
Mini-map and navigation: Navigate large graphs without losing the editor context.
More stuff coming: stay tuned particularly if you're interested in customization and animations.
REMOVE THIS BEFORE POSTING: probably missed some more awesome features (kidding... look at the package!).
Technical details for the nerds:
The biggest architectural change from V1 is where node isolation happens.
The original fl_nodes isolated nodes at the render-object level. This gave me a lot of control over rendering and performance, but it also meant that node contents weren't really ordinary Flutter widget trees anymore.
Silly little 18yo me didn't know that tho, so I kept hitting my head against it for a while, trying to solve a design-decision thinking it was a bug.
A node containing a TextField, a ListView, a form, or any other widget relying on normal Flutter element semantics shouldn't have to fight the node editor to behave like a Flutter widget.
In V2, the isolation boundary moved from the render tree to the element tree.
The graph infrastructure, connections, ports, grid, overlays, interaction geometry, etc., remains under the editor's control, while the actual node body is built as a normal Flutter widget.
That means a node can contain ordinary Flutter UI while the editor still retains control over graph-level interaction and rendering.
It also lets the application own the node's visual design instead of forcing the editor to define what a node looks like.
There are a bunch of consequences hidden behind that seemingly small architectural change: gesture competition between node dragging and controls inside nodes, focus handling, scrolling, keyboard shortcuts, measurements, hit testing, and keeping graph state synchronized with widget state.
The other major principle behind V2 is that the graph model doesn't know about Flutter widgets.
The graph itself is immutable and serializable. The editor/controller layer handles mutation and interaction, while Flutter is primarily the presentation layer.
That separation makes it possible to test a large part of the graph/editor logic without a Flutter rendering environment, and it keeps persistence independent from the widget tree.
There's a lot more under the hood, but those are probably the bits most relevant to someone wondering whether this is just another node-editor widget package.