Node vs Subflow Node implementation research

Has anybody done research to compare resource usage when creating nodes using subflows vs writing the same functionality using a single node using js?

I'm wondering if it's possible to estimate the performance improvement—expressed as a percentage—for each Node-RED subflow that is replaced by a custom node written in pure JavaScript. The idea is to focus specifically on the overhead introduced by using subflows compared to native JS nodes, assuming all other logic remains the same.

If a reasonably consistent approximation exists—perhaps varying slightly depending on the target architecture or Node.js binary—we could use it in a Node-RED plugin to suggest flow optimizations. For instance, the plugin might say:
"This subflow could be rewritten as a JavaScript node, potentially reducing memory usage by 15%. Would you like to use an AI model to help generate it?"

It would be a plugin such as Google Lighthouse but for Node-RED flows

My hypothesis is:

Subflows introduce measurable overhead(memory, CPU, increase of time moving messages) compared to equivalent native JavaScript nodes, even when implementing identical functionality.

@knolleary @dceejay @gregorius

I would suspect also that subflows have an overhead, just as flows have an overhead compared to pure JS code. It's the trade off between visual and textual. How much overhead that is - don't know.

I have never looked but I wonder how much is optimised when a flow is executed, for example, are junction nodes removed by linking nodes directly before the flow is started?

How much of the structure of the flow is maintained, i.e., how are message sent between nodes - is there a lookup table that a node consults before sending or does a node send directly to other nodes because it knows what to call? This is something that I did away with in Erlang-Red - the flows send message directly to the nodes and the overall flow structure is dissolved on the server, i.e., I can't reconstruct the original flow because all nodes become processes and they send their messages to a process id and not a node id.

Are nodes "inlined" before execution? Is there a type of compile step where node-code might be inlined into other nodes. For example is the code for subflows "inserted" into the flow at the places where it is referenced?

I guess it would be a great research topic: building a compiler for visual code (not just NR but a more generalised form of visual code).

1 Like

I stopped using subflows once Node-red introduced groups & link-calls, which gives the same reusability.

Subflows have various limitations & peculiarities, but to your point, they impact performance since they are actually just macros: each subflow instance is a replica of the subflow template, i.e. if a subflow is composed of 30 nodes, and is defined 10 times in the flow, in effect it creates 300 nodes (and this grows exponentially).This consumes memory and also increases the flow size and its load, initialization & save time
.
In contrast, when you define a reusable group and call it from multiple places with link calls, it is instantiated only once.

1 Like

I wasn't considering the duplication of the nodes of a subflow when you duplicate the subflow node. Thank you for reminding me about that.

I was really just thinking about comparing 1 node with 1 subflow node, both with the same functionality, and measure the overhead the subflow implementation added.

I will try to do this research later once i finish my framework to write nodes and rewrite the salesforce nodes. Then I will use the results to convince people to give it a try to implement nodes using my framework.

Thanks @gregorius for the good questions

1 Like

I had never used subflows for that reason, however I had a lot of dashboard1 groups with the same ui nodes repeated many times. Creating a subflow for this reduced the clutter from around 16 nodes to 1 subflow node. The fact that duplicating the subflow increases resource use is not an issue as the ui nodes existed before anyway.