# Support for node status list and duration

**URL:** <https://discourse.nodered.org/t/support-for-node-status-list-and-duration/97735>\
**Category:** Feature Requests\
**Created:** [22 June 2025 09:02 UTC](https://discourse.nodered.org/t/support-for-node-status-list-and-duration/97735 "2025-06-22T09:02:24Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![GogoVega](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/gogovega/32/71313_2.png) [@GogoVega](https://discourse.nodered.org/u/GogoVega)\
**Post date:** [22 June 2025 09:02 UTC](https://discourse.nodered.org/t/support-for-node-status-list-and-duration/97735/1 "2025-06-22T09:02:24Z")

</div>

Follow [Pull request proposal - temporary node status](https://discourse.nodered.org/t/pull-request-proposal-temporary-node-status/28081) :

I stumbled upon this interesting topic by chance.

I would have a suggestion with the following format:

```ts
type NodeStatusFill = "red" | "green" | "yellow" | "blue" | "grey";
type NodeStatusShape = "ring" | "dot";

interface NodeStatus {
  fill?: NodeStatusFill;
  shape?: NodeStatusShape;
  text?: string;
  duration?: number;
}

// Node object
status(status: string | NodeStatus | NodeStatus[]): void;

```

If the parameter is an object, the end of duration clears the status. And if it's an array, the end of duration displays the next status. When the last status is reached, if it contains a duration, it clears the status.

Note: in the array, objects must have a duration (except the last element of the array) otherwise the status is ignored.

---

<div class="post-metadata">

**Author:** ![Steve-Mcl](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/steve-mcl/32/4826_2.png) [@Steve-Mcl](https://discourse.nodered.org/u/Steve-Mcl)\
**Post date:** [22 June 2025 13:25 UTC](https://discourse.nodered.org/t/support-for-node-status-list-and-duration/97735/2 "2025-06-22T13:25:04Z")

</div>

That thread generated a lot of good ideas but ultimately the details were not pinned down.

Sticking points:

- Should these temporary statuses trigger the status node? Nick had a strong opinion of yes (no exceptions)
- Should the status revert to previous _previous\_state_ after `duration` expires?
  - IMO that is an excellent opportunity to simplify showing inflight status without having to worry about maintaining or recomputing the original state and adding it to the end of an array. For example the node can be "connected" but you want to temporarily show a message of "Insert Done" or "Next event in 10 mins" or "..."
  - e.g.:
  - ![animated-status](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/9/a/9ad36c89345a0948f13575b4a66e14f1605ae601.gif)
  - if it does revert, do we send the "connected" status again? if yes, then there should be a means of letting the user know this is a repeat (a `duplicate` flag or something to let the user know it hasnt JUST happened now)
    - **reason** : a flow might be monitoring the status and performing setup logic on the status becoming "connected". If status was resent everytime without a means to understand if it is a duplicate, the user will have to resort to setting context values to "remember".

Regarding your suggestion about an array: IMO, it does not _easily_ solve the original need to be able to provide temporary status info having to either maintain a copy of the current state or re-compute the current state and add it to the end of the array.

  

> **Inner thoughts**
>
> I have deliberately hidden this as I am not confident I have covered all bases and there is implementation detail too - so not ideal for spit balling! I was very close to deleting it all because it will probably muddy waters. However, in the end, I decided to just leave it here, hidden, in case it spurs thoughts or provides an angle not considered, or ends up forming part of the final solution.
> 
> _Feel free to ignore._
> 
>   
> 
> if I were asked to implement something today, and was given free reign, this is what comes to my mind...
> 
> - As today, any call to status with the well established value of `string` | `NodeStatus` would be considered **sticky** and should emit the status ⚡
> - If the status includes a `duration` property, it should update the status text and emit the new status⚡After the duration expires, it should revert back to the **sticky** state and also emit the reverted status ⚡.
> - If the status includes a `duration` and `noEmit: true` prop, do NOT emit the status 🚫. After the duration has expired, it should revert back to the **sticky** status and NOT (re)emit the **sticky** status 🚫
> 
> | order of events | emits |
> | --- | --- |
> | node.status({ text: "online" }) | ⚡ |
> | node.status({ text: "processing", duration: 3000 }) | ⚡ |
> | (core) node.statusRevert() | ⚡(with `duplicate` flag or similar) |
> | node.status({ text: "processing", duration: 3000, noEmit: true }) | 🚫 |
> | (core) node.statusRevert() | 🚫 |
> 
> Any temporary status send during a temporary status should replace the current temporary status and follow the above rules.
> 
> ### Benefits.
> 
> 1. Clear and (i think) simple rules
> 2. Node developer can send a status, at any time, without ever having to keep track of existing **sticky** status via some global _current\_state_ object or have to recompute the current state and send our another status containing the _current\_state_ as we do today
> 3. Can provide temporary statuses without emitting and therefore not affecting users init code (e.g. the `noEmit` flag would prevent duplicate "online" type status re-emitting)
> 4. Can provide temporary statuses with emitting (so that user can consume the temporary status) however they can still ignore the reverted emit by inspecting the `duplicate` flag
> 
> ### Parts I dont like
> 
> - the necessary evil magic flags required to permit the user to interpret the status messages and thus avoid re-running initialisation logic triggered by a specific state
> - One way of potentially solving this without flags in the status messages: the status node could have an option of "fixed only" (default / as is today), "in-flight only", "all". This might simplify matters and remove the need for any flags since the user would be able to ignore temporary statuses. Likewise, if they do only want to watch for inflight events, they could set it to "in-flight only"
> 
> - Everything I have write in this hidden section
> - The fact I am actually gonna post this noise 🫣
> 
>   
> 
> ok, I am talking myself out of this altogether - there are lots of considerations need to be made :yikes:

---

<div class="post-metadata">

**Author:** ![AllanOricil](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/allanoricil/32/106911_2.png) [@AllanOricil](https://discourse.nodered.org/u/AllanOricil)\
**Post date:** [22 June 2025 13:38 UTC](https://discourse.nodered.org/t/support-for-node-status-list-and-duration/97735/3 "2025-06-22T13:38:51Z")

</div>

> [@Steve-Mcl](#):
>
> node.status({ text: "processing", duration: 3000 }) ⚡ (core) node.statusRevert() ⚡(with `duplicate` flag or similar)

I’m not in favor of using `node.statusRevert()` because it can make code maintenance more difficult. When reading the code, you’re forced to mentally simulate its execution just to understand the status changes, since the final state isn't explicitly written out. This adds unnecessary cognitive load. It's much clearer when the node's status is explicitly defined at each step, allowing readers to understand the current state without having to debug or trace the flow of execution.

For the same reason, I prefer that the status is simply cleared after a certain duration, and Im not in favor of the status change based on the duration. If the node developer wants to display a different status, they should explicitly call the status method with the new state. This approach keeps the status flow transparent and easier to follow.

---

<div class="post-metadata">

**Author:** ![Steve-Mcl](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/steve-mcl/32/4826_2.png) [@Steve-Mcl](https://discourse.nodered.org/u/Steve-Mcl)\
**Post date:** [22 June 2025 14:02 UTC](https://discourse.nodered.org/t/support-for-node-status-list-and-duration/97735/4 "2025-06-22T14:02:13Z")

</div>

> [@AllanOricil](#):
>
> I’m not in favor of using `node.statusRevert()` because it can make code maintenance more difficult.

I understand your take but disagree. The status reversion (in theory) simplifies DX by allowing the author to fire-and-forget inflight temporary status without having to programmatically maintain actual prior state or recompute it and add it to the end of an array.

Consider a plugin or a bit of code that does not have access to the internals of your code (and therefore has no idea what _current state_ is) it would not be able to do the status reversion. Ok, that is a somewhat contrived example (it was off the top of my head) but I think some kind of auto revert is better because it removes the need to maintain or recompute the original state.

That said, an alternative might be to have something like `node.getState()` so that the suggested array method could be used as follows: `node.status([{text: 'my temporary inflight status', duration 3000}, node.getState()]) // revert to existing state`

Or, a callback in the status object that forces the developer to provide the fallback e.g.

```auto
const inflightTempStatus = {
  "my temp status",
  duration: 3000,
  onComplete: () => {
    node.status(getCurrentStatus())    
  }
}
node.status(inflightTempStatus)

```

> [@AllanOricil](#):
>
> With the same argument, I prefer that after the duration the status is cleared and disappear. If the developer of the node wants to show a different status he must invoke the status method with a new given status.

The original thread was created to simplify transient messages without affecting the "status-quo" (hence the "temporary" bit). What you are saying here is kinda already possible if you think about it. e.g:

```auto
node.status("temp message")
await sleep(3000)
node.status("")

```

---

<div class="post-metadata">

**Author:** ![GogoVega](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/gogovega/32/71313_2.png) [@GogoVega](https://discourse.nodered.org/u/GogoVega)\
**Post date:** [22 June 2025 14:03 UTC](https://discourse.nodered.org/t/support-for-node-status-list-and-duration/97735/5 "2025-06-22T14:03:00Z")

</div>

> [@Steve-Mcl](#):
>
> it does not _easily_ solve the original need to be able to provide temporary status info having to either maintain a copy of the current state or re-compute the current state and add it to the end of the array

Because I haven't taken it into account - by default the behavior should be `clear` but we can add a `retain` or `restore` property that will restore the initial status. e.g. `retain` in one element or `restore` in the last element. (first status is the initial status)

---

<div class="post-metadata">

**Author:** ![Steve-Mcl](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/steve-mcl/32/4826_2.png) [@Steve-Mcl](https://discourse.nodered.org/u/Steve-Mcl)\
**Post date:** [22 June 2025 14:06 UTC](https://discourse.nodered.org/t/support-for-node-status-list-and-duration/97735/6 "2025-06-22T14:06:57Z")

</div>

> [@GogoVega](#):
>
> Because I haven't taken it into account - by default the behavior should be `clear` but we can add a `retain` or `restore` property that will restore the initial status. e.g. `retain` in the first element or `restore` in the last element

Again, that does not consider my (somewhat contrived) situation:

> [@Steve-Mcl](#):
>
> Consider a plugin or a bit of code that does not have access to the internals of your code (and therefore has no idea what _current state_ is) it would not be able to do the status reversion. Ok, that is a somewhat contrived example (it was off the top of my head) but I think some kind of auto revert is better because it removes the need to maintain or recompute the original state.

And as I said to Allan:

> [@Steve-Mcl](#):
>
> The original thread was created to simplify transient messages without affecting the "status-quo" (hence the "temporary" bit). What you are saying here is kinda already possible if you think about it. e.g:
> 
> ```auto
> node.status("temp message")
> await sleep(3000)
> node.status("")
> 
> ```

Lastly, we are now getting into the weeds again without fully clarifying things like should temporary status emit etc.

---

<div class="post-metadata">

**Author:** ![GogoVega](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/gogovega/32/71313_2.png) [@GogoVega](https://discourse.nodered.org/u/GogoVega)\
**Post date:** [22 June 2025 14:10 UTC](https://discourse.nodered.org/t/support-for-node-status-list-and-duration/97735/7 "2025-06-22T14:10:38Z")

</div>

Okay, I see what you mean, I'll think about it - I have to finish wiring an electrical panel 😅

> [@GogoVega](#):
>
> Note: in the array, objects must have a duration (except the last element of the array) otherwise the status is ignored.

Thinking about it, it's better to use a default duration if not set (for elements before the last)

---

<div class="post-metadata">

**Author:** ![AllanOricil](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/allanoricil/32/106911_2.png) [@AllanOricil](https://discourse.nodered.org/u/AllanOricil)\
**Post date:** [22 June 2025 15:15 UTC](https://discourse.nodered.org/t/support-for-node-status-list-and-duration/97735/8 "2025-06-22T15:15:40Z")

</div>

> [@Steve-Mcl](#):
>
> I understand your take but disagree. The status reversion (in theory) simplifies DX by allowing the author to fire-and-forget inflight temporary status without having to programmatically maintain actual prior state or recompute it and add it to the end of an array.

I'll apply a bit of Socratic strategy here and let you answer this question for yourself as you compare the two examples. Try reasoning through it on your own.

Could you tell us which code is less cognitive challenging to determine the current status of a node in a given line?

```js
node.status({ fill: "blue", shape: "dot", text: "Waiting for input..." });

node.on("input", async (msg) => {
    node.status({ fill: "yellow", shape: "dot", text: "Validating..." });

    try {
        const isValid = await validate(msg.payload);
        if (!isValid) {
            node.status({ fill: "red", shape: "ring", text: "Invalid input" });
            setTimeout(() => {
                node.statusRevert(); // ← What will it revert to here?
            }, 3000);
            return;
        }

        node.status({ fill: "green", shape: "dot", text: "Processing..." });

        const result = await process(msg.payload);
        node.send({ payload: result });

        node.statusRevert(); // ← What will the status revert to now?
    } catch (err) {
        node.status({ fill: "red", shape: "ring", text: "Error occurred" });
        setTimeout(() => {
            node.statusRevert(); // ← Multiple places reverting... revert to what?
        }, 5000);
    }
});

```

This example creates several cognitive challenges:

- You need to trace back what the original status was.
- The meaning of each statusRevert() depends on where and when it’s called. It is necessary to ACCUMULATE context in your memory about the previous lines of code to be able to determine the status the node will be reverted to.
- The mental model of status flow becomes increasingly hard to maintain as the code grows.

```js
const DEFAULT_STATUS = { fill: "blue", shape: "dot", text: "Waiting for input..." };
node.status(DEFAULT_STATUS);

node.on("input", async (msg) => {
    node.status({ fill: "yellow", shape: "dot", text: "Validating..." });

    try {
        const isValid = await validate(msg.payload);
        if (!isValid) {
            node.status({ fill: "red", shape: "ring", text: "Invalid input" });
            setTimeout(() => {
                node.status(DEFAULT_STATUS); // Explicit and clear
            }, 3000);
            return;
        }

        node.status({ fill: "green", shape: "dot", text: "Processing..." });

        const result = await process(msg.payload);
        node.send({ payload: result });

        node.status(DEFAULT_STATUS); // No ambiguity
    } catch (err) {
        node.status({ fill: "red", shape: "ring", text: "Error occurred" });
        setTimeout(() => {
            node.status(DEFAULT_STATUS); // You always know what it becomes
        }, 5000);
    }
});

```

Benefits:

- No guesswork — the final status is always visible in the code.
- Easier to debug and maintain.
- Safe with concurrent inputs.
- Clear separation of concerns: status is treated as intentional state, not a side-effect to be "undone."

Please, if you have counter arguments, quote the argument as well. You quoted only the statement of my previous comment. This makes it harder for people to interpret and review the discussion.

---

<div class="post-metadata">

**Author:** ![GogoVega](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/gogovega/32/71313_2.png) [@GogoVega](https://discourse.nodered.org/u/GogoVega)\
**Post date:** [22 June 2025 15:29 UTC](https://discourse.nodered.org/t/support-for-node-status-list-and-duration/97735/9 "2025-06-22T15:29:48Z")

</div>

Each status that doesn't contain either `retain` or `duration` **is retained** as the status to restore, as well as `retain=true`.

When `duration` is set, the default behavior is **clear** , and if `restore` is set, the behavior is now to restore the initial status. It may be a bit tedious, but it's the only way I see to avoid breaking the existing status. Like Allan, I don't really like the `statusRevert` method.

I don't know if clear as default behavior is the best solution because it depends on the usage. e.g. mqtt node will prefer to restore the initial status while function node will clear the current status.

---

<div class="post-metadata">

**Author:** ![TotallyInformation](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/totallyinformation/32/31_2.png) [@TotallyInformation](https://discourse.nodered.org/u/TotallyInformation)\
**Post date:** [22 June 2025 16:52 UTC](https://discourse.nodered.org/t/support-for-node-status-list-and-duration/97735/10 "2025-06-22T16:52:52Z")

</div>

Not sure I've completely understood this thread so if this is not relevant, please ignore.

My thought - and hopefully one that maintains the best possible backwards compatibility - would be to add a _new_ status type. That way, the original status would continue to act just as it does now. And so would the status node.

Then you could have a completely separate "live status". You could extend the status node to be triggered on these or ignore them. So avoiding all of the issues regarding rolling back to a previous state - you wouldn't need to. But, a flow using a status node could easily be extended to deal with temporary status changes if you wanted to. But you wouldn't be forced to.

For custom nodes, the issuing of a "live status" would overwrite any existing actual status and, on timeout, would simply revert. There would not be any need to re-issue the old status (now current again) because the status node understands they are different and your _flow_ handles it, not the node.

As I say, this feels that it should be 100% backwards compatible with minimal changes needed to core. It also keeps the 2 concepts somewhat separated which, in my weird brain at least, seems easier to comprehend.

So the workflow would be:

1. Trigger a standard, static status if you want - using the current functions.
2. On receipt of a suitable event or msg, trigger a "live status" using a new RED function to be created in core. That fn will have access to the current non-live status automatically via reference to the node data, see the next para for why that is important. When the live status times out, all it has to do is restore the visual to the current non-live status (if set), nothing else.

If your flow updates the standard status while the live status is active, then the current status function would still be triggered and any connected status node would also be triggered, however, the display would not update (that might need to be an option). But because the new live status function "knows" the current non-live status setting, as the timeout expires, it will automatically set the display to the correct status.

Not sure if any of that makes sense, it has been a very long week for me and my brain is a little burned out.

---

<div class="post-metadata">

**Author:** ![GogoVega](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/gogovega/32/71313_2.png) [@GogoVega](https://discourse.nodered.org/u/GogoVega)\
**Post date:** [22 June 2025 17:49 UTC](https://discourse.nodered.org/t/support-for-node-status-list-and-duration/97735/11 "2025-06-22T17:49:16Z")

</div>

Backward compatibility will be respected.

The request concerns:

- duration for the status
- the ability to provide a list of statuses to display with a duration for each
- restore a previous status

If a status has no duration and/or has `retain=true`, it will be saved. When a status has `restore=true` (and therefore a duration), at the end of this duration, the status will be replaced by the saved one. If there is no `restore`, the status will be clear. As I mentioned just above, perhaps the most useful behavior would be to reverse it: by default, restore the saved status, and otherwise, if `clear=true`, clear the status.

---

<div class="post-metadata">

**Author:** ![Steve-Mcl](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/steve-mcl/32/4826_2.png) [@Steve-Mcl](https://discourse.nodered.org/u/Steve-Mcl)\
**Post date:** [22 June 2025 19:40 UTC](https://discourse.nodered.org/t/support-for-node-status-list-and-duration/97735/12 "2025-06-22T19:40:37Z")

</div>

> [@AllanOricil](#):
>
> Could you tell us which code is less cognitive challenging to determine the current status of a node in a given line?
> 
> ```auto
> node.status({ fill: "blue", shape: "dot", text: "Waiting for input..." });
> 
> node.on("input", async (msg) => {
> node.status({ fill: "yellow", shape: "dot", text: "Validating..." });
> 
> try {
> const isValid = await validate(msg.payload);
> if (!isValid) {
> node.status({ fill: "red", shape: "ring", text: "Invalid input" });
> setTimeout(() => {
> node.statusRevert(); // ← What will it revert to here?
> }, 3000);
> return;
> }
> 
> node.status({ fill: "green", shape: "dot", text: "Processing..." });
> 
> const result = await process(msg.payload);
> node.send({ payload: result });
> 
> node.statusRevert(); // ← What will the status revert to now?
> } catch (err) {
> node.status({ fill: "red", shape: "ring", text: "Error occurred" });
> setTimeout(() => {
> node.statusRevert(); // ← Multiple places reverting... revert to what?
> }, 5000);
> }
> });
> 
> ```

↑ quoted code will be addressed below in **"Clarification on the assumptions"**

> [@AllanOricil](#):
>
> This example creates several cognitive challenges:
> 
> - You need to trace back what the original status was.
> - The meaning of each statusRevert() depends on where and when it’s called. It is necessary to ACCUMULATE context in your memory about the previous lines of code to be able to determine the status the node will be reverted to.
> - The mental model of status flow becomes increasingly hard to maintain as the code grows.

↑ I will address these at the end

#### Clarification on the assumptions

Your example code wrongly assumed some things from my hidden proposal (in which I stated something along the lines of not being fully fleshed out )

But just in case this ever comes to a conclusion I should clarify I suppose. The idea of the status reversion is that it is simple to use and works the same for everyone. It is not an implementation detail but rather a feature implemented by the core. In its implementation (as stated) it would take care of maintaining the **sticky state** (even if that is updated while a temporary status is in-flight - i.e. there is no contention)

#### Your code example of my hidden proposal (updated)

This is an update to the code you assumed would look like - its been fleshed out a little more to represent a rather basic node with a config that updates connection status

```js
configNode.on('connect', () => {
    node.status({ fill: "green", shape: "dot", text: "connected" })
})
configNode.on('disconnect', () => {
    node.status({ fill: "gray", shape: "dot", text: "disconnected" })
})
configNode.on('error', (err) => {
    node.status({ fill: "red", shape: "ring", text: "error: " + err.message })
})

/**
 * Helper function for clean code purposes only.
 * Calls node.status with proposed duration & noEmit flags which instruct core to not emit
 * the status change and to revert to the last known status after the specified duration.
 */
const tempStatus = (text, shape="ring", fill="yellow", duration=3000, emit=false) => node.status({ fill, shape, text, timeout: duration, emit })

node.on("input", async (msg) => {
    if (!configNode.isConnected) {
        return
    }
    tempStatus("Processing input...") // yellow ring, 3s, by default

    try {
        const isValid = await validate(msg.payload)
        if (!isValid) {
            throw new Error("Invalid input")
        }
        const result = await process(msg.payload)
        tempStatus("Processing successful", "dot", "green") // green dot, 3s, noEmit
        node.send({ payload: result })
    } catch (err) {
        node.error("Processing failed", msg) // catchable error (msg.error will contain the details)
        tempStatus("Processing failed", "dot", "red", 5000) // show error for 5 seconds
    }
})

```

##### Benefits

- Better DX
- Not an implementation pattern that is open to interpretation
- Not litter with timers or global status memories
- Flags on the status object provide clear intent

Note there are no calls to this _`statusRevert`_ it would be handled by the core code (as implied in the `(core)` text in the table)

  

> [@AllanOricil](#):
>
> ```auto
> const DEFAULT_STATUS = { fill: "blue", shape: "dot", text: "Waiting for input..." };
> node.status(DEFAULT_STATUS);
> 
> node.on("input", async (msg) => {
> node.status({ fill: "yellow", shape: "dot", text: "Validating..." });
> 
> try {
> const isValid = await validate(msg.payload);
> if (!isValid) {
> node.status({ fill: "red", shape: "ring", text: "Invalid input" });
> setTimeout(() => {
> node.status(DEFAULT_STATUS); // Explicit and clear
> }, 3000);
> return;
> }
> 
> node.status({ fill: "green", shape: "dot", text: "Processing..." });
> 
> const result = await process(msg.payload);
> node.send({ payload: result });
> 
> node.status(DEFAULT_STATUS); // No ambiguity
> } catch (err) {
> node.status({ fill: "red", shape: "ring", text: "Error occurred" });
> setTimeout(() => {
> node.status(DEFAULT_STATUS); // You always know what it becomes
> }, 5000);
> }
> });
> 
> ```

I have a few critiques of this but I will stick with 2.

1. There is nothing in your code example that requires any changes to core as of today. What you are proposing is an pattern that I, you or anyone could (and probably does) do this today - but that was not the requirement of the original OP.
2. Because it is an pattern - it is open to interpretation and all developers follow these to the letter and never make mistakes `/s`

Taking the approach you demonstrated above, to achieve a temporary status (like the original OP intended) for the scenario "simple node with config" I demonstrated above, your pattern of reverting the status to its last known **sticky** state is a lot trickier...

```js
let STICKY_STATUS = null; // global status variable will contain "something"
let timer1
let timer2
configNode.on('connect', () => {
    STICKY_STATUS = { fill: "green", shape: "dot", text: "connected" };
    node.status(STICKY_STATUS);
})
configNode.on('disconnect', () => {
    STICKY_STATUS = { fill: "gray", shape: "dot", text: "disconnected" };
    node.status(STICKY_STATUS);
})
configNode.on('error', (err) => {
    STICKY_STATUS = { fill: "red", shape: "ring", text: "error: " + err.message };
    node.status(STICKY_STATUS);
})

node.on("input", async (msg) => {
    node.status({ fill: "yellow", shape: "dot", text: "Validating..." });

    try {
        const isValid = await validate(msg.payload);
        if (!isValid) {
            node.status({ fill: "red", shape: "ring", text: "Invalid input" });
            timer1 = setTimeout(() => {
                node.status(STICKY_STATUS); // change status back to the last known state from THIS code's POV
            }, 3000);
            return;
        }

        node.status({ fill: "green", shape: "dot", text: "Processing..." });

        const result = await process(msg.payload);
        node.send({ payload: result });

        node.status(STICKY_STATUS); // change status back to the last known state from THIS code's POV
    } catch (err) {
        node.status({ fill: "red", shape: "ring", text: "Error occurred" });
        clearTimeout(timer1); // clear previous timer if it exists
        timer2 = setTimeout(() => {
            node.status(STICKY_STATUS); // change status back to the last known state from THIS code's POV
        }, 5000);
    }
});

node.on("close", () => {
    // prevent any pending status changes when the node is closed
    clearTimeout(timer1);
    clearTimeout(timer2);
});

```

Now lets compare the two approaches:

1. **First Approach** :
  - Lines of code: 28
  - The flags are explicit - meaning it is clear these are temporary status changes.
  - Inline timers: None (the core handles reverting status automatically).

2. **Second Approach** :
  - Lines of code: 42
  - Implementation relies on a global variable to maintain the last known state.
    - requires each developer to implement this pattern in their code.
    - requires each developer to remember to revert the status back to the last known state.

  - The status is reverted to the last known state after a delay
    - this may or may not be desired (core has no say here, will blindly revert to stored status unless extra logic is implemented)
    - requires additional logic to handle timer cancellations for successive inputs (concurrency protection) and for clean up to avoid stray timers (node close event)

  - Inline timers: required to revert the status after a delay

Also, I have not commented on how a status change coming from another place (like a hook in your node or an event from a config - IDK - I am just adding flavour at this point to try and iluminate why core implementation is preferable). With a core implementation, the core would take care or status reversion, timer cancelations, clean up etc.

So to address the benefits you state:

> [@AllanOricil](#):
>
> - No guesswork — the final status is always visible in the code.

Agreed. But as state above, down to each developer and their implementation.

> [@AllanOricil](#):
>
> - Easier to debug and maintain.

Disagree. `setTimeout` is akin to "hit and hope". There are so many edge cases jumping of the screen especially related to fast successive messages and stale state.

> [@AllanOricil](#):
>
> - Safe with concurrent inputs.

Disagree. See above point

> [@AllanOricil](#):
>
> - Clear separation of concerns: status is treated as intentional state, not a side-effect to be "undone."

Disagree. It is not a side effect if it is by design.

  

And lastly to address the stated "cognitive challenges:"

> [@AllanOricil](#):
>
> - You need to trace back what the original status was.

No, you dont. This is an assumption. My intent (like the original OP) was it would be a core feature.

> [@AllanOricil](#):
>
> - The meaning of each statusRevert() depends on where and when it’s called. It is necessary to ACCUMULATE context in your memory about the previous lines of code to be able to determine the status the node will be reverted to.

Again, an assumption. The core implementation would (should) take care of this for users of the API in the same consistent manor for all callees.

  

* * *
  

Allan, I hope you can agree, responding in this manner, when assumptions easily made, is exhausting! I am more than happy to discuss implementation details when a clear proposal is laid down.

In future, unless responses are first clarified (to avoid any assumptions) by way of first asking for clarification, I will not be replying to large bodies of text like this again.

Sorry. I do love your enthusiasm and detail and all, but this is exhausting mate.

* * *

Final disclaimer - even though I have gone through this and (in my head) I feel there is a solution to achieve the original OP, I am not 100% confident I have covered all edge cases nor have I considered every node~contrib~pligin interaction. And in the end, this post and my hidden proposal that spurned this, could just end up being utter nonsense and noise (because I missed a critical detail or Nick says no for some valid reason) - this is why we should be pinning down the proposal not the implementation details.

---

<div class="post-metadata">

**Author:** ![AllanOricil](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/allanoricil/32/106911_2.png) [@AllanOricil](https://discourse.nodered.org/u/AllanOricil)\
**Post date:** [22 June 2025 19:46 UTC](https://discourse.nodered.org/t/support-for-node-status-list-and-duration/97735/13 "2025-06-22T19:46:31Z")

</div>

> [@GogoVega](#):
>
> If a status has no duration and/or has `retain=true`, it will be saved. When a status has `restore=true` (and therefore a duration), at the end of this duration, the status will be replaced by the saved one. If there is no `restore`, the status will be clear. As I mentioned just above, perhaps the most useful behavior would be to reverse it: by default, restore the saved status, and otherwise, if `clear=true`, clear the status.

I'm uncertain about the usefulness of the `restore` and `retain` feature values. I’m not comfortable with the idea of the core automatically changing the status without an explicit, imperative call, to something different than clearing it. This implicit behavior makes the code harder to reason about — a developer would have to scroll back to where the status was originally set in order to understand why it was retained or restored to a particular value.

That said, I do agree that the initial implementation of the duration feature should simply clear the status after a specified number of milliseconds. If `node.status()` is called again before the duration expires, the previous timer should be cancelled, and a new one should start only if the new call also includes a duration. This ensures that status updates remain predictable, avoid overlap or race conditions, and are easier to debug and reason about.

---

<div class="post-metadata">

**Author:** ![AllanOricil](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/allanoricil/32/106911_2.png) [@AllanOricil](https://discourse.nodered.org/u/AllanOricil)\
**Post date:** [22 June 2025 19:56 UTC](https://discourse.nodered.org/t/support-for-node-status-list-and-duration/97735/14 "2025-06-22T19:56:36Z")

</div>

> [@Steve-Mcl](#):
>
> Again, an assumption. The core implementation would (should) take care of this for users of the API in the same consistent manor for all callees.

I'm sorry, but I think you did not understand the main point of the argument. The second example demonstrates that I don't need to read previous lines of code to determine the new status. While in the first example, which used `node.revertStatus()`, I must read previous lines to determine which status it will be reverted to. And because I need to accumulate information in my brain about a previous context, it can become hard to debug status changes. It is not "assumption", it is logical reasoning. When a piece of code is more cognitive challenging to interpret, its maintenance could become harder for people who did not participated in the development.

---

<div class="post-metadata">

**Author:** ![GogoVega](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/gogovega/32/71313_2.png) [@GogoVega](https://discourse.nodered.org/u/GogoVega)\
**Post date:** [22 June 2025 20:04 UTC](https://discourse.nodered.org/t/support-for-node-status-list-and-duration/97735/15 "2025-06-22T20:04:42Z")

</div>

> [@AllanOricil](#):
>
> I'm uncertain about the usefulness of the `restore` and `retain` feature values.

If we don't find an agreement, it will be ignored.

But I must admit that in my nodes I need to store the status to restore it later, so Steve's request corresponds to a use I have.

`retain` is optional; it allows a temporary status to be the new saved status.

---

<div class="post-metadata">

**Author:** ![Steve-Mcl](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/steve-mcl/32/4826_2.png) [@Steve-Mcl](https://discourse.nodered.org/u/Steve-Mcl)\
**Post date:** [22 June 2025 20:25 UTC](https://discourse.nodered.org/t/support-for-node-status-list-and-duration/97735/16 "2025-06-22T20:25:32Z")

</div>

> [@AllanOricil](#):
>
> I'm sorry, but I think you did not understand the main point of the argument.

But I do. Let me paraphrase you to show that do.  
You are saying that by being explicit on the setting of status that at "read time" (as in human reading the code) it will be easier for them to understand when and why the status changes.  
Thus the benefit in debugging.

However, you are clearly missing my points about 1) simplified DX, 2) actually achieving the feature request and 3) doing it in a controlled way in the core so that is is not left open to dev implementation and all the edge cases like race conditions, dangling timers firing after node close, all the mistakes EVERYONE makes are avoided.

The fact there is some "magic" goes on in the core to achieve the OP in my rough outline is besides the point. Even if it makes the "read time" dev have to head off to RTFM to understand "why", the benefits outweigh simply the negatives IMO. Lets face it, there is magic everywhere and when a codebase gets so large that your brain cannot parse it in one screenful, you end up implementing the same pattern over and over and mistakes (and deviations) occur.

> [@GogoVega](#):
>
> If we don't find an agreement, it will be ignored.

↑ Exactly this ↑

This kind of to & fro is what left the original post to rot.

---

<div class="post-metadata">

**Author:** ![AllanOricil](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/allanoricil/32/106911_2.png) [@AllanOricil](https://discourse.nodered.org/u/AllanOricil)\
**Post date:** [22 June 2025 20:45 UTC](https://discourse.nodered.org/t/support-for-node-status-list-and-duration/97735/17 "2025-06-22T20:45:42Z")

</div>

> [@Steve-Mcl](#):
>
> However, you are clearly missing my points about 1) simplified DX, 2) actually achieving the feature request and 3) doing it in a controlled way in the core so that is is not left open to dev implementation and all the edge cases like race conditions, dangling timers firing after node close, all the mistakes EVERYONE makes are avoided.

For 3, I understand the concern of not trusting on node authors to properly destroy/reset timers. When developers forget about doing it, several issues can happen, such as memory leaks, race conditions, resource waste or undesired side effects. However I believe this type of issue should be solved differently, like using `no-unused-vars` with eslint/biome. If EVERYONE is making this issue we need to address the root cause and not place it under the carpet and pretend it doesnt exist. [My analogy was dumb so i removed it]

I think 2 is a more of a solution to solve what you said in 3 than actually a solution that provides a better DX. `node.revertStatus()` will lead to more cogntive challenging code, like I explained above. If it is more challenging to interpret I don't agree it improves DX. Maybe it facilitates the life of who is writting the code at the moment he/she is writting it because this person will have the context in his brain, but it makes it harder for people who are going to maintain it later.

[removed this third paragraph because I realized it was unecessary]

---

<div class="post-metadata">

**Author:** ![dceejay](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/dceejay/32/38_2.png) [@dceejay](https://discourse.nodered.org/u/dceejay)\
**Post date:** [22 June 2025 21:40 UTC](https://discourse.nodered.org/t/support-for-node-status-list-and-duration/97735/18 "2025-06-22T21:40:56Z")

</div>

Must admit my current 2 cents worth is to agree with [@totallytinformation](https://discourse.nodered.org/t/support-for-node-status-list-and-duration/97735/10) way back above. The "temporary status" to me feels like maybe it ought to be a completely different call that just so happens to overlay the screen space of the status, and always reverts once timed out. By having a separate call you know that it is always going to be temporary, and it can explicitly NOT trigger the status node, and does not start overloading the existing status api with loads of possible flags, timeouts, etc.

---

<div class="post-metadata">

**Author:** ![Steve-Mcl](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/steve-mcl/32/4826_2.png) [@Steve-Mcl](https://discourse.nodered.org/u/Steve-Mcl)\
**Post date:** [22 June 2025 22:28 UTC](https://discourse.nodered.org/t/support-for-node-status-list-and-duration/97735/19 "2025-06-22T22:28:26Z")

</div>

> [@dceejay](#):
>
> Must admit my current 2 cents worth is to agree with [@totallytinformation](https://discourse.nodered.org/t/support-for-node-status-list-and-duration/97735/10) way back above. The "temporary status" to me feels like maybe it ought to be a completely different call that just so happens to overlay the screen space of the status

I do also agree somewhat but must admit to carrying baggage from the original op (i.e. all status changes should trigger status node - so worked that into the proposal)

If we massage the language and instead call it a "temporary status overlay" and its purely for visual purposes, then that should satisfy the OP.

In a way, it is not too far off my gimmicky gif:

> [@Steve-Mcl](#):
>
> ![animated-status](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/9/a/9ad36c89345a0948f13575b4a66e14f1605ae601.gif)

  

_tho, to throw a virtual spanner in the works, the devil in me is hearing the future cries of "how can I this read this temporary status value"_

---

<div class="post-metadata">

**Author:** ![dceejay](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/dceejay/32/38_2.png) [@dceejay](https://discourse.nodered.org/u/dceejay)\
**Post date:** [22 June 2025 23:12 UTC](https://discourse.nodered.org/t/support-for-node-status-list-and-duration/97735/20 "2025-06-22T23:12:21Z")

</div>

Re spanner. Yes as I said in the original thread, how long is temporary ? If it’s too short I may miss it. If I’m on another tab and miss it does it matter ? If a tree falls and no- one is around, does it make a sound ? Etc… My take is that these are purely informational in the moment, so shouldn’t affect (real) status.

[Next page](https://discourse.nodered.org/t/support-for-node-status-list-and-duration/97735.md?page=2)
