Managing State in Node-RED: Choosing Between Node, Flow, and Global Context
Stop losing data between triggers. Learn how to use Node, Flow, and Global context in Node-RED to manage state and persist data across restarts.
31 May 2026, 18:36 UTC

The Problem: The Stateless Nature of Event-Driven Flows
Node-RED is fundamentally event-driven. A message arrives at a node, the node processes it, and the message moves forward. Once that message leaves the node, the node "forgets" everything about it. This creates a significant challenge when you need to remember a value from a previous trigger—such as calculating the difference between the current temperature reading and the last one, or tracking a user's progress through a multi-step form.
To solve this, Node-RED provides a Context system. Context allows you to store data outside the immediate msg object, enabling you to maintain state across asynchronous events. The core engineering decision is not whether to use context, but which scope of context is appropriate for your data.
Understanding the Context Hierarchy
Node-RED organizes state into three distinct layers. Choosing the wrong one can lead to memory leaks, namespace collisions, or data that vanishes after a reboot.
Node Context (Local)
Node context is private to a single node. No other node in the entire workspace can access it. This is ideal for internal counters or temporary flags that only matter to that specific piece of logic.
Flow Context (Tab-level)
Flow context is shared among all nodes on a single tab (flow). If you have a "Climate Control" tab and a "Security" tab, nodes in Climate Control can share data via Flow context without interfering with the Security tab. This is the recommended default for most state management tasks.
Global Context (Instance-level)
Global context is accessible by every node in every flow across the entire Node-RED instance. While powerful, it is risky. If two different flows use a variable named status in the Global scope, they will overwrite each other, leading to unpredictable behavior.
Worked Example: Creating a Delta Trigger
Imagine you want to trigger an alert only if a temperature sensor increases by more than 2 degrees since the last reading. You cannot do this with a standard msg object because the previous value is gone by the time the new message arrives.
Add a Function Node between your sensor and your alert logic. Use the following JavaScript (assuming Node-RED v1.0+):
// Retrieve the previous temperature from Flow context
// The second argument is a default value if the key doesn't exist yet
let lastTemp = flow.get('lastTemp') || 0;
let currentTemp = msg.payload;
let delta = currentTemp - lastTemp;
// Update the Flow context with the current temperature for the next run
flow.set('lastTemp', currentTemp);
if (delta > 2) {
msg.payload = `Temperature rose by ${delta} degrees!`;
return msg;
} else {
return null; // Stop the flow if the change is insignificant
}
Verification Steps
- Deploy the flow.
- Use an Inject node to send a value (e.g., 20). The flow will return null (delta is 20-0, but it's the first run).
- Inject 21. The flow returns null (delta is 1).
- Inject 24. The flow triggers the alert (delta is 3).
- Open the Context Data sidebar in the Node-RED editor to visually confirm that
lastTempis currently 24.
Persistence and Performance Trade-offs
By default, context is stored in volatile memory (RAM). If you restart Node-RED or the server crashes, all your flow.set and global.set data is wiped.
To make state survive restarts, you must modify the settings.js file. Under the contextStorage property, you can enable local file system storage:
contextStorage: {
default: {
module: "localfilesystem"
}
}
The Trade-off: Persisting context to disk introduces I/O overhead. If you are updating a global variable 100 times per second, writing to the disk on every update will significantly degrade performance. For high-frequency data, keep the state in memory or use a dedicated time-series database.
Limitations and Best Practices
- Not a Database: Context is for state, not storage. Do not store large arrays or complex relational datasets in context; use MongoDB or PostgreSQL for that.
- Namespace Collision: Avoid generic names like
valueortempin Global context. Use prefixes, such asglobal.set('hvac_livingroom_temp', 22). - Memory Management: Be cautious with
global.setin loops. If you dynamically create keys without clearing them, you will create a memory leak that eventually crashes the Node-RED process.
Summary Decision Matrix
| Requirement | Recommended Scope | Storage Risk |
|---|---|---|
| Internal node logic | Node | Low |
| Shared logic within one feature | Flow | Medium |
| System-wide configuration | Global | High (Collisions) |
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.