Building Reusable Logic in Node‑RED with Subflows
Learn how to encapsulate common functionality into Node‑RED subflows, see a JWT‑validation example, and understand the trade‑offs before adopting this pattern in your own flows.
15 Mar 2026, 12:39 UTC

Problem: Repeating the Same Logic Across Flows
When you start wiring together HTTP endpoints, device data, or cloud services in Node‑RED, it’s common to need the same piece of logic in many places—validating a JWT token, formatting timestamps, or normalising sensor readings. Copy‑pasting a function node each time works, but any change requires hunting down every duplicate, increasing the chance of drift and bugs.
Thesis: Subflows Let You Package Logic Once and Reuse It Safely
A subflow is a self‑contained group of nodes that appears as a single node on the main canvas. By moving repeated logic into a subflow, you get a single source of truth, easier version control via flows.json, and the ability to share the subflow across multiple projects through the palette or export/import.
When to Use a Subflow
- The same set of nodes (input → processing → output) appears in three or more flows.
- You want to hide implementation details while exposing a clean interface (e.g., a token‑validation node that accepts
msg.headers.authorizationand outputsmsg.useron success or throws an error on failure). - You plan to version‑control the logic independently of the surrounding flow.
If the logic is a single line of JavaScript or only used once, a subflow adds unnecessary indirection.
Worked Example: JWT Validation Subflow
We’ll create a subflow that expects an Authorization: Bearer <token> header, verifies the signature using a shared secret, and passes the decoded payload downstream. The example uses the built‑in function node for simplicity; in production you might replace it with a dedicated node-red-contrib-jwt node.
1. Build the Subflow
- Open the Node‑RED editor (
http://localhost:1880). - From the menu choose Subflows → Create Subflow. Name it
jwt-validate. - Add an input node (the subflow’s entry point).
- Add a function node with the following code (replace
YOUR_SECRETwith your actual secret or an environment variable):// Expect msg.headers.authorization like "Bearer <token>" const auth = msg.headers?.authorization || ''; const match = auth.match(/^Bearer\s+(.+)$/i); if (!match) { node.error('Missing or malformed Authorization header', msg); return; } const token = match[1]; try { // Simple HMAC‑SHA256 verification (for demo only) const crypto = require('crypto'); const [encodedHeader, encodedPayload, signature] = token.split('.'); if (!encodedHeader || !encodedPayload || !signature) throw new Error('Invalid token format'); const data = `${encodedHeader}.${encodedPayload}`; const expected = crypto.createHmac('sha256', 'YOUR_SECRET').update(data).digest('base64url'); if (signature !== expected) throw new Error('Signature mismatch'); const payload = Buffer.from(encodedPayload, 'base64url').toString('utf8'); msg.user = JSON.parse(payload); return msg; } catch (err) { node.error(err.message, msg); return; } - Add an output node (the subflow’s exit point).
- Click Done to close the subflow editor.
The subflow now appears in the palette under Subflows as jwt-validate. It has one input and one output.
2. Use the Subflow in a Flow
- Drag an http in node onto the canvas, set Method to
GETand URL to/protected. - Drag the
jwt-validatesubflow node from the palette and connect it after the http in node. - Add a function node that returns a success message:
return {payload: `Hello, ${msg.user.name || 'user'}!`}; - Add an http response node and connect it.
- Deploy the flow.
When you call GET http://localhost:1880/protected with a valid JWT in the Authorization header, the subflow decodes the token, attaches msg.user, and the final function node returns a greeting. If the token is missing or invalid, the subflow calls node.error, which stops further processing and returns an HTTP 500 (you can add a catch node to return a custom 401).
Trade‑offs and Limitations
- Debugging visibility: Errors inside a subflow are logged with the subflow’s node ID, which can make tracing harder than seeing the raw function node. Mitigate by adding a
debugnode inside the subflow during development and removing it before production. - Performance overhead: Each subflow adds a small message‑passing cost. For extremely high‑throughput paths (tens of thousands of messages per second), a plain function node may be preferable.
- Versioning: Because the subflow definition lives in
flows.json, updating it requires redeploying all flows that use it. Treat subflows like libraries—update them intentionally and test downstream flows.
Actionable Closing
Start by identifying a piece of logic you’ve copied at least three times. Extract it into a subflow using the steps above, then replace the duplicates with the subflow node. Verify the behavior by deploying a test flow and calling the endpoint with both valid and invalid inputs (use curl -H "Authorization: Bearer <valid‑token>" http://localhost:1880/protected and a malformed token to see the error response). Keep an eye on the Node‑RED logs for any node.error outputs, and adjust the subflow’s error handling to match your API’s contract. This approach gives you a single source of truth, easier collaboration, and a cleaner main canvas—without sacrificing the flexibility Node‑RED is known for.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.