🎉 Node-RED 5.0.0 Beta 6 available

:tada: One more beta of Node-RED 5 is now available. Following some of the feedback (and bugs) with the last beta, we wanted to get one more out to make sure we've addressed everything we need to before the final release.

The changelog lists out all of the PRs in this release: node-red/CHANGELOG.md at dev · node-red/node-red · GitHub

Install-free Demo

If you have a WebKit-based browser (eg Chrome), and possibly Firefox, you can preview the release here:

Node 22 is now the minimum supported Node.js version

Node-RED now requires a minimum of Node 22.9.0 to run. It will refuse to start on anything earlier.

Node 24 is the recommended version to run with. The docker images are based on Node 24 - and the plan will be to only provide Node 24 images (adding Node 26 when it becomes available).

UX updates

There are no significant changes on the UX with this beta - mostly just fixing up the various items flagged to us with the last beta.

Improved accessibility has been a common theme in the UX work, and the Dark theme has received a number of updates. We've also started applying appropriate aria attributes across the editor; there will always be more to do around accessibility, but Google Lighthouse is much nicer about us than it was before.

Away from the editor UX, there have been a few new items in this release worth highlighting

Calling Link nodes from the Function node

It is now possible to call a Link node from the middle of a Function node and wait for a response to be sent back. For example, if you created a flow, wrapped in Link nodes, to handle queries to a database, you could call it in code with:

const { payload: data } = await node.linkcall('query-database', { query: "SELECT * FROM T1" })

The new api is exposed as node.linkcall. You pass it the name, or id, of the link in node to call and the message to pass it.

There's more to it than just that - check the PR for full details. We still need to get this added to the documentation.

See Defining utility functions for re-use in a function node by Steve-Mcl · Pull Request #5494 · node-red/node-red · GitHub for details Thanks to @Steve-Mcl for working on this.

Bundling npm as part of Node-RED

Previously, Node-RED relied on npm being installed and on the path for the palette manager to be able to do its thing.

With this release, we now include npm as an explicit dependency of Node-RED. This gives us more control on how its used and closes some potential security issues.

Updated developer setup

For contributors to the core code base, we've now migrated away from the grunt task runner tool in favour of custom npm scripts. Grunt was the right choice 13 years ago, but the world has moved on, and, finally, so have we. This allows us to drop a lot of devDependencies from the project that weren't being maintained.

We've also moved off the long-dormant jshint to eslint. At this stage, we're not applying any new linting rules, but it lays the groundwork for that in the near future.

Check the PRs for more details:


Installing the beta

If you want to try out the beta, you will need specify node-red@next when you use npm to update. Without the @next you'll still get 4.1.x

So on a Pi you'd do:

sudo npm install -g --unsafe-perm node-red@next

Docker images

The beta images are available under nodered/node-red-dev:v5.0.0-beta.6 - with the default image being based on Node 24.

Reporting problems

If you hit any problems, please report them either as a reply on this topic, or in the #core-dev slack channel. Please do not post new topics to the forum regarding the beta as that could confuse users who are not using the beta.

What's Next

I've said it before, but this should be the final beta release. From this point forward I'm focussed on getting the final release done by the end of May, if not sooner.

3 Likes

There's still that blue border around the panel / sidebar buttons:

image

Side bar is (now) working as designed :folded_hands:

I dont think this is anything to get upset about.
But the highlight/selected border - is sized at time of selection, if after a status is updated (and still selected), it doesn't re-size.

:pinching_hand: detail - but thought id mentioned it

Thank you for the fixes

Well thats controversial :wink:

Surprised you are going to ESLINT v9. I think that v10 is much better for complex repo's since it finally goes back to using (or at least allowing) multiple config files allowing - hopefully - much simpler configs for different environments (e.g. browser vs node.js).

Happy to discuss possible configs/extensions if helpful. Bit of a rabbit hole of course as you will likely end up with a LOT of errors being highlighted due to the use of a lot of var entries etc. Great for finding hidden bugs though.

Strictly speaking, it is "Calling (visual) subroutines from within a function node in the same execution context"
It permits someone who is writing code in a function and needs to call-out (to grab a value/format a thing) to take advantage of re-usable code (be that something in a library of utility functions in a function node OR a little utility flow that uses other core/contrib nodes OR ...).

Man, it is difficult to easily explain or portray the possibilities that it opens up, but hopefully it doesnt take too long to realise the doors opened by this).

The graphic and demo flow in this comment might provide some additional context. There was also a rather long and detailed discussion in the discourse thread that discussed various options and approaches to the whole reusable question. The first post is worth a read to understand the rationale. I also know it will not be what suits everyone nor provide solution to every scenario, but it was the best of a bunch of options in terms of what it brings vs effort etc.

4 Likes

Oh dont get me wrong! - It's awesome!!!
A recent update I pushed allows (Opt in) direct comms inside a Function Node to a ZWave Network.

But couldn't help pull the legs on it :grin:

Wow, calling links from inside function nodes breaks the visual contract. It’s now no longer be possible to understand flows just visually, this will require looking into function nodes.

Crazy how this opens now the possibility of creating a single function that just does everything :slight_smile:

2 Likes

That's the focus indicator. Important for accessibility, but something to look at refining.

Good spot. A status refresh doesn't trigger the full redraw of the node.

As I said above, one step at a time. We will be banishing all the vars and applying standard linting. But the first iteration was to switch over the tool chain with minimal impact.

@ralphwetzel (from the beta5 thread) will look at the deploy button's drop-down trigger to not appear disabled when it is clickable

I am certain your post is missing a /s but...

As do link call nodes (kinda) but there was a requirement for reusable routines, this offers it in a way somewhat conducive to VFP.

Not quite. But i get the joke. You dont have to use it :stuck_out_tongue_winking_eye:

It's just inconsistent - from my POV. The other buttons don't show this indicator after being operated.

That said - another detail: When you move the focus frame (by pressing TAB) to another button in the lower-right-hand button-strip ... you cannot activate a panel / sidebar by pressing SPACE.

Ah man, I missed that, nice catch! (thats normally the first thing I check). Looks like the handler is not on the click event! The search, zoom, update, etc buttons do work correctly tho.

EDIT:

It is on mouseup, so I immediately checked what happens when a user lets go of a dragged node with the mouse over a toolbar button - it triggers it.

chromeJSjeVSN8Zv

Can't say I'm a fan of this feature whatsoever.

It sure does

I don’t have to use it but it makes understanding flow code harder for the benefit of…

And reuse - hm ok, I’ll have a look at the examples but i really can’t imagine what use case could be so important that the visual-only understanding of flows could be broken.

Because once this is possible, even if I don’t use it, someone else might. So I’m still left with looking into each function node… but hey, AI will do that for me :wink:

2 Likes

Looks like the selection border of nodes with a button on the right side needs additional (right hand) padding.

"Button-left" style looks good:

2 Likes

That actually looks OK to me. I wouldn't personally worry about that.

Good design is good design. The flow author(s) should always be responsible for clear and parsable flows regardless of what features are in use.

Yes, it might enable a flow that isn't quite as easy to follow. But it adds a fair bit of flexibility and power to Node-RED.

Not sure if I'll ever use it but I think it is a useful feature.

Holimoli, of course. That's why C code is consistently good and solid code without any memory leaks or memory overwriting. Yes, if good programmers are doing good stuff, yes you will get good code. Now if you don't happen to have good coders ... well ... the less they can break, the better!

No. I definitely see this as a problematic change.

Because control flow should always be visual. The point I'm trying to make is that control flow and data flow is clear in NR because it has to flow along pipes. This change breaks this contract. Suddenly data can silently flow along hidden pipes.

Worse, even if I don't use it, then I still have the challenge that any function node not from me might be doing this side-effect coding. So I still have to have a look for these side effects.

I would really really really (yes really 3 "really"s there) think about making side-effect calls from function nodes possible. It's really letting the cat out of the bag ... it's the genie out of the bottle ... but that's my take, each to their own.

To put it another way: it's a code smell if you need to be calling link nodes from a function node :slight_smile:

2 Likes

I’m also against allowing Link Call usage inside Function nodes. What use case does that unlock that can’t already be handled through standard wiring?
If it’s only meant as a convenience utility, then I’d also push for my PR that added native support for working with Set and Map in JSONata to be merged. That change was genuinely useful because it removes the need to rely on Function nodes just to manipulate Set or Map structures. Otherwise, users are forced into custom Function nodes, which unnecessarily bloats the final flow.json whenever those data structures are used.

Can users use RED.nodes.getNode from function nodes? I'm asking because this would be another way to bypass the visual contract mentioned above if suddenly function nodes could call receive of other nodes

Screenshot 2026-05-01 at 08.30.28

[{"id":"38bf73a4a0a6c063","type":"function","z":"a3eacd3cd06ac2b4","name":"function 2","func":"msg.payload = RED.nodes.getNode(\"38bf73a4a0a6c063\")\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":800.5,"y":555,"wires":[["8f912175cffb3907"]]},{"id":"f897d52a858b915d","type":"inject","z":"a3eacd3cd06ac2b4","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":558,"y":572,"wires":[["38bf73a4a0a6c063"]]},{"id":"8f912175cffb3907","type":"debug","z":"a3eacd3cd06ac2b4","name":"debug 27","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":1127,"y":551,"wires":[]}]

so no, generally there is no introspection allowed in the function node.

There is also an issue with backward compatibility - I can now not be guaranteed that flows created in NR 5.x will work on NR <= 4.x.

Just to clarify that. We all don't work in C because of it's flexibility and subtleties, so we have higher level languages that have memory management (via garbage collection for example) or string manipulation routines (so that pointer overruns are avoided) etc

NR does this as well by defining nodes that limit the scope of functionality (plus the fact that it uses NodeJS which is in itself an abstraction). Of course, the disadvantage is that not everything can be done in a "simple" ways or in ways that the NR design foresaw. But what is the NR design? Does it imply that flow control and data flow are clearly visually understandable? I would argue yes. For me, it's a central core promise of NR: "control flow/data flow will always be visual".

If that is not the case, then this change (link calling from function nodes) is fine. But then why both with a link call node? I could just use a function node everywhere instead. Or even the link out node, I could replace that with a function node. What is the difference between the use cases - when do I use a function node and when do I use the link nodes? Extra confusion for newbies.

At this point, a small reminder: Unix principle "do one task and one task only but do it well". The function node becoming a swiss army knife breaks that principle. But if that's the desired outcome, then so be it.

For anyone jumping straight into the middle of this thread - to be sure there is no misunderstanding, this feature does not simply send a msg to a link node. It replicates the link-call capability providing a means of calling utility flows.

I hear the concern regarding code smell, but I’d argue that it actually reduces smell (or wiring spaghetti). Currently, if a flow developer in a function node needs a piece of logic already existing elsewhere (either in another function node or in a flow), they have some common 'smelly' choices (non exhaustive):

  1. Duplicate the logic: Duplicate the function/flow's logic in JS inside the Function node (WET).
  2. Context hopping: Break the function in 2, save the internal variables & state to context flow/global, wire it out to the reusable flow and push it into a second function node (or change node/whatever node), retrieve store state, then process etc.

node.linkcall provides a third, cleaner way. it treats a visual flow as a first class function. Its not about making or promoting Node-RED as a pure coding environment, it’s permitting common battle hardened logic 'flow' to be more useful to the 'code'."

There are lots of threads saying things like "Can I call a node from inside the function", "how can i call/resuse my calculateThing function/flow from other places without duplicating", etc etc. And yes, a good deal of them were code smell, but some are not (addressed below)

Speaking from experience on some node-red installations - sometimes there is no other (straight forward) way to achieve a solution without resorting to a function node. Sometimes, within the context of execution of that function, you need to call something outside of it and await the reply. Typically this is when you have imported an npm lib in the function setup (specialised code with no suitable contrib package) & leaving execution means resorting to hoop jumping / storing state of live objects in context (akin to global variables) / semaphore interlocking for synchronisation / implementing busy flags / etc, then picking up the result and context after the external operations are done. A simple await in the context of the function execution is now possible. From the point of view of the function code environment this feature removes smell (albeit at the expense of a piece of visual wiring - an effort vs benefit thing).

To put this in terms a traditional programmer might relate. It eliminates the VFP equivalent of "callback hell" that I will call "asynchronous spaghetti" (for want of better terms). Standard node wiring requires breaking a function into 2 parts: "pre-logic" and "post-logic.". This adds cognitive load due to splitting a complex function up just to call an external routine requiring you to manually manage state and then retrieve that state when the external part is done. await node.linkcall(...) maintains the local scope of the function. It turns a "callback hell" (async spaghetti) of wired nodes into a clean, readable, linear execution path. It’s not about avoiding wiring, it’s about avoiding unnecessary state management overhead in those times when a function is the only way.


Summary:

argument counter
function nodes are bad Function nodes can sometimes be a technical necessity for complex tasks where an NPM module is required (where no contrib node equivalent exists). This feature ensures those necessary code blocks don't become isolated 'black boxes' that cant leverage other parts of the flow.
should use standard wiring Leaving a functions execution to use standard wiring destroys local scope & forces "context hopping" (manually saving/loading state) which is brittle and error prone!
code smell Hardcoding logic in JS that already exists in a flow is smell. This feature simply promotes reuse and better design by allowing a flow to be reused (that includes functions/contribs/core nodes) for those times when a function node is the only (sane) way of achieving the goal - all while remaining DRY.
3 Likes

As a muggle NodeRED user, I have to agree that letting functions invisibly call link nodes seems to go against the basic philosophy of NR.

If there was a method of visually indicating that a function node might call out of the flow then maybe it would be OK

2 Likes