Expert guidance for Node-RED flow-based programming. Use when working with Node-RED flows (JSON), creating custom nodes, configuring settings.js, debugging flows, or integrating with MQTT, HTTP, WebSocket, and Home Assistant. Triggers on tasks involving flow design, node development, automation workflows, and IoT integrations.
Resources
1Install
npx skillscat add szkocot/skills/nodered Install via the SkillsCat registry.
Node-RED
Node-RED is a flow-based programming tool for event-driven applications, enabling visual wiring of nodes to create automation workflows.
Core Concepts
Message Object
Messages flow between nodes via msg object:
{
payload: "data", // Primary data
topic: "category", // Message type/category
_msgid: "abc123" // Auto-generated ID
}Node Types
- Input: Inject, HTTP In, MQTT In - initiate flows
- Processing: Function, Change, Switch - transform data
- Output: Debug, HTTP Response, MQTT Out - send results
- Utility: Delay, Trigger, Split/Join - control flow
Flow JSON Structure
Flows stored in flows.json:
[
{
"id": "node-uuid",
"type": "inject",
"name": "Timer",
"repeat": "5",
"payload": "hello",
"payloadType": "str",
"x": 100,
"y": 100,
"wires": [["next-node-id"]]
},
{
"id": "next-node-id",
"type": "debug",
"name": "Output",
"active": true,
"complete": "payload",
"x": 300,
"y": 100,
"wires": []
}
]Key properties:
id: Unique UUIDtype: Node type namex, y: Editor positionwires: Array of arrays mapping outputs to next node inputs
Function Node
Execute JavaScript with full context access:
// Access message
const data = msg.payload;
// Modify message
msg.payload = data.toUpperCase();
msg.timestamp = Date.now();
// Send to output
return msg;
// Multiple outputs
return [msg1, msg2];
// Send nothing
return null;Context Storage
// Node context (this node only)
context.set("key", value);
const val = context.get("key");
// Flow context (all nodes in flow)
flow.set("counter", 0);
const count = flow.get("counter");
// Global context (all flows)
global.set("config", {});
const cfg = global.get("config");Async Operations
// Using async/await
const result = await someAsyncFunction();
msg.payload = result;
return msg;
// Using node.send() for async
someAsyncFunction().then(result => {
msg.payload = result;
node.send(msg);
});
return null; // Don't return msg hereCommon Nodes
Change Node
Modify message properties without code:
- Set:
msg.payloadto value - Change: Replace text in property
- Move: Rename property
- Delete: Remove property
Switch Node
Route messages based on conditions:
==,!=,<,>,<=,>=contains,matches regexis null,is not nullis of type(string, number, etc.)
Template Node
Mustache templating:
Hello {{payload.name}}!
Temperature: {{payload.temp}}°CIntegrations
MQTT
Subscribe (MQTT In):
Topic: home/sensors/#
QoS: 0/1/2
Output: parsed JSON or stringPublish (MQTT Out):
Topic: home/commands/light
Retain: true/false
QoS: 0/1/2HTTP
Create endpoint (HTTP In → HTTP Response):
Method: GET/POST/PUT/DELETE
URL: /api/dataMake request (HTTP Request):
Method: GET
URL: https://api.example.com/data
Return: parsed JSONWebSocket
Real-time bidirectional communication:
- WebSocket In: Listen for messages
- WebSocket Out: Send to clients
Debugging
Debug Node
- Output to sidebar panel
- Show complete msg or specific property
- Add to status bar
Console Logging
// In function node
node.warn("Warning message"); // Yellow, shows in debug
node.error("Error message"); // Red, triggers catch
console.log(msg); // Terminal onlyStatus Indicators
node.status({
fill: "green", // green, yellow, red, grey
shape: "dot", // dot, ring
text: "connected"
});
node.status({}); // Clear statusError Handling
Catch Node
Catches errors from nodes in same flow:
[Any Node] → error → [Catch Node] → [Handle Error]Try/Catch in Function
try {
const result = JSON.parse(msg.payload);
msg.payload = result;
return msg;
} catch (e) {
node.error("Parse failed: " + e.message, msg);
return null;
}Configuration (settings.js)
Location: ~/.node-red/settings.js
module.exports = {
// Server
uiPort: 1880,
httpAdminRoot: '/admin',
httpNodeRoot: '/api',
// Flows
flowFile: 'flows.json',
credentialSecret: "your-secret-key",
// Security
adminAuth: {
type: "credentials",
users: [{
username: "admin",
password: "$2b$08$hash...", // bcrypt hash
permissions: "*"
}]
},
// Logging
logging: {
console: { level: "info" }
},
// Context storage
contextStorage: {
default: { module: "memory" },
persistent: { module: "localfilesystem" }
},
// Function node globals
functionGlobalContext: {
moment: require('moment'),
_: require('lodash')
}
};Home Assistant Integration
Use node-red-contrib-home-assistant-websocket:
Call Service Node
Domain: light
Service: turn_on
Entity: light.living_room
Data: {"brightness": 255}Entity Node
Monitor state changes:
Entity: sensor.temperature
Output on: state changeGet Entities Node
Query current state:
Search: entity_id contains "light"
Output: array of entitiesReference
- Custom nodes - Full node development guide
- Flow patterns - Common automation patterns
- Home Assistant - HA integration details