Node-RED to GitOps — When to Graduate from Flows to Functions
A practical guide comparing flow-based programming (Node-RED) with the function-based GitOps approach used by fn-uns. When to use each, how to migrate, and why code-first wins when you need to scale, collaborate, and maintain a production UNS.
Start with Node-RED — Seriously
If you're exploring whether a Unified Namespace makes sense for your factory, start with Node-RED. We mean it.
Node-RED is the fastest way to wire MQTT topics together and see results. You can go from "I have a PLC publishing data" to "I have a dashboard showing machine status" in an afternoon. No code, no containers, no deployment pipeline — just drag, drop, and connect.
What Node-RED Does Brilliantly
- ✓ Instant feedback — wire an MQTT-in node to a debug node and you're watching live data in seconds
- ✓ Visual data flow — you can literally see how data moves from source to destination
- ✓ Low barrier to entry — manufacturing engineers and automation specialists can build flows without being software developers
- ✓ Rich ecosystem — thousands of community nodes for OPC UA, Modbus, S7, databases, dashboards
- ✓ Rapid prototyping — test an idea in minutes, not days
- ✓ Built-in dashboard — Node-RED Dashboard gives you gauges, charts, and buttons with zero frontend code
A Typical Node-RED UNS Experiment
Here's what a first UNS experiment looks like in Node-RED — and it's genuinely effective:
# A simple Node-RED flow for UNS experimentation [MQTT In] → v1.0/enterprise/site1/area1/cnc-01/status ↓ [Function] → Parse JSON, extract state field ↓ [Switch] → Route by state: ACTIVE / IDLE / ALARM / SETUP ↓ [Dashboard] → Gauge showing current state ↓ [PostgreSQL] → INSERT INTO machine_log (topic, state, timestamp) # Total setup time: ~30 minutes # Nodes used: 6 # Lines of code: 0 (just node configuration)
This is a perfectly valid way to prove the concept. You've demonstrated that machine data flows through MQTT, gets processed, gets stored, and gets visualised. The business case is proven.
The question is: what happens next?
Same Logic, Different Delivery
The core logic of a UNS pipeline is the same regardless of whether you implement it in Node-RED or fn-uns. The difference is how that logic is packaged, deployed, and maintained.
Example: Detecting a Machine State Change
Node-RED Approach
An MQTT-in node subscribes to v1.0/#. A function node compares the incoming value to a context variable storing the previous value. If changed, it passes the message to a PostgreSQL node that inserts a row. The logic lives inside the function node's text editor — a small JavaScript snippet embedded in the flow JSON.
fn-uns Approach
uns-framework (Go) subscribes to MQTT and caches current + previous values in Valkey. uns-state (Go) reads the cache, compares values, and writes state transitions with durations to PostgreSQL. Each is a standalone program in its own directory with its own Dockerfile, tests, and README.
Example: Logging Data to a Database
Node-RED
Wire a function node to a PostgreSQL node. The function node builds the SQL query as a string. Table creation is manual — you run the CREATE TABLE statement separately. If the schema changes, you update the function node and hope you don't break the query.
fn-uns
Each function auto-creates its table on first run with CREATE TABLE IF NOT EXISTS. The schema is defined in the same file as the business logic. Schema changes are version-controlled — you can see exactly when a column was added and why.
Example: Computing a KPI
Node-RED
A function node queries PostgreSQL, computes utilisation as ACTIVE time divided by total time, and outputs the result to a dashboard gauge. The SQL query, the calculation logic, and the output formatting all live inside one function node's code editor.
fn-uns
uns-kpi is a standalone Go function (250 lines) that queries all PostgreSQL tables and returns a structured JSON response with utilisation, availability, throughput, MTBF, MTTR, and stoppage pareto. Filterable by machine, area, and time range. Testable. Documented.
The logic is identical. The delivery mechanism is fundamentally different — and that difference matters enormously as you scale.
When Flows Stop Scaling
Node-RED flows work beautifully at small scale. The problems emerge gradually — and by the time you notice them, you're deeply invested.
The Progression
The Seven Problems
| Problem | What Happens | Real-World Impact |
|---|---|---|
| No version control | Flows are stored as a JSON blob in Node-RED's runtime database. There's no native git integration, no commit history, no branches. | Someone changes a flow on Friday afternoon. Monday morning it's broken. Nobody knows what changed. You can export the JSON and diff it, but a 5,000-line JSON diff is unreadable. |
| No code review | Changes go live the moment you click Deploy. There's no pull request, no approval process, no second pair of eyes. | A well-intentioned change to the stoppage classification logic silently breaks the KPI calculation. Nobody catches it for two weeks because there's no review process. |
| Single runtime | All flows run in one Node.js process. One bad function node — an infinite loop, an unhandled exception, a memory leak — crashes everything. | Your state tracking, your historian, your KPI calculation, your dashboard — all down because one experimental node had a bug. At 3am. On a Saturday. |
| Untestable | There's no standard way to unit test a Node-RED flow. You can't run automated tests before deploying. You can't validate that a change doesn't break existing behaviour. | Every deployment is a manual test. "Deploy and pray." The more complex the flow, the more likely a change has unintended side effects. |
| Multi-site replication | To deploy the same logic to 5 factories, you export the flow JSON and import it at each site. Configuration differences (broker addresses, machine names) require manual editing. | Site 3 is running a version from last month. Site 5 has a local modification that nobody documented. Keeping them in sync is a full-time job. |
| Team collaboration | Two people editing the same flow at the same time will overwrite each other's changes. There's no merge, no conflict resolution. | The automation engineer and the IT engineer both need to make changes. One deploys, the other deploys, the first person's changes are gone. |
| Debugging at scale | A flow with 200 nodes across 8 tabs becomes a visual maze. Following data through the flow requires clicking into each node to read its configuration. | When something goes wrong, you're clicking through nodes one by one trying to find where the data path diverges. The visual advantage becomes a visual nightmare. |
Manufacturing Engineer
You built the original flows and they work great for your line. But now management wants the same thing across all 4 sites, and the IT team is asking how to maintain it. The flows that were your strength are becoming your bottleneck — you're the only person who understands them.
Developer
You've been asked to "productionise" the Node-RED flows. But there's no test suite, no CI/CD, no way to do a code review. The business logic is scattered across function nodes with names like "Function 3" and "transform data". You'd rather rewrite it than maintain it.
IT Engineer
You need to run this across multiple sites with consistent configuration, monitoring, and update procedures. But Node-RED is a single process with no health checks, no independent scaling, and no way to update one piece of logic without redeploying everything. Your change management process doesn't work with "click Deploy."
Why GitOps Wins for Production
GitOps means git is the single source of truth for your system. Every function, every configuration, every deployment is a git commit. This isn't a philosophical preference — it's a practical requirement for production manufacturing systems.
Head-to-Head Comparison
| Capability | Node-RED | fn-uns + GitOps |
|---|---|---|
| Version history | Export JSON manually, diff is unreadable | Full git log — every change, every author, every reason |
| Branching | Not possible — one runtime, one version | Standard git branches — develop features in isolation |
| Code review | Not possible — changes go live on Deploy | Pull requests with line-by-line diffs and approval |
| Rollback | Manual — re-import a previous JSON export (if you have one) | git revert + git push — instant, safe, audited |
| Testing | Manual — deploy and check | Unit tests, integration tests, CI/CD pipelines |
| Failure isolation | One bad node crashes everything | Each function is its own container — failures are isolated |
| Multi-site deploy | Export/import JSON per site, manual config changes | git push to each site — identical, reproducible |
| Collaboration | Shared runtime — last deploy wins | Branches + merge — parallel work without conflicts |
| Audit trail | Platform-dependent, often none | Git commits with author, date, message, and diff |
| Reproducibility | Import JSON, hope dependencies match | git clone + docker compose up — identical environment every time |
| Onboarding | Click through nodes to understand the flow | Read the code, read the README, run the tests |
The Deployment Workflow
Node-RED Deployment
Open the editor → make changes → click Deploy → hope it works → if it doesn't, try to remember what you changed → manually revert by re-importing an old export (if you saved one). No approval. No review. No rollback safety net.
fn-uns Deployment
Edit the function → test locally with docker compose up → commit with a message explaining why → push → fnkit builds and deploys automatically. To rollback: git revert + git push.
# The fn-uns deployment workflow # 1. Make a change vim uns-state/function.go # 2. Test locally cd uns-state && docker compose up -d curl http://localhost:8080/uns-state | jq # 3. Commit with context git add . git commit -m "add MTBF calculation to state tracker Reads ACTIVE→ALARM transitions from uns_state table and computes mean time between failures per machine. Requested by maintenance team for predictive scheduling." # 4. Push to deploy git push deploy main # 5. If something goes wrong git revert HEAD git push deploy main # → Previous version is running again in seconds
The Migration Path
You don't throw away your Node-RED work. The logic you prototyped in Node-RED becomes the specification for your production functions. Every flow maps to a function.
From Flow to Function
The Mapping
Every Node-RED concept has a direct equivalent in fn-uns:
| Node-RED Concept | fn-uns Equivalent | What Changes |
|---|---|---|
| Flow (tab) | Function directory | Each flow becomes its own directory with its own container |
| MQTT-in node | uns-framework | One Go program subscribes to all topics and caches in Valkey |
| Function node | function.go / index.js | The JavaScript snippet becomes a proper program with error handling |
| Context variables | Valkey cache | In-memory context becomes a shared, persistent cache |
| PostgreSQL node | Database calls in code | SQL is in the same file as the logic — visible, testable, version-controlled |
| Dashboard nodes | uns-dashboard (Grafana) | Grafana dashboards with SQL queries, version-controlled as JSON |
| Deploy button | git push | Deployment is audited, reversible, and automated |
| Flow export (JSON) | Git repository | Full history, branching, merging, code review |
fn-uns Equivalents
Here's how fn-uns handles every common Node-RED UNS pattern — and what you gain by making the switch.
MQTT Subscribe & Cache
Node-RED
MQTT-in node → function node that stores flow.set('prev_' + topic, value) in context. Previous values are lost on restart. Context is local to the Node-RED instance.
fn-uns: uns-framework
Go program subscribes to v1.0/#, writes current + previous to Valkey. Persistent across restarts. Shared across all functions. Includes metadata (message count, first_seen, last_updated).
State Change Detection
Node-RED
Function node compares msg.payload.state to flow.get('last_state'). Duration calculated with Date.now() - flow.get('state_since'). Logic is 15 lines of JavaScript inside a node config dialog.
fn-uns: uns-state
150-line Go program with proper error handling, in-memory state tracker per machine, precise duration calculation, and automatic table creation. Reads from Valkey, writes completed states to PostgreSQL with state, duration_s, and next_state.
Stoppage Classification
Node-RED
Switch node routes by state → function nodes map IDLE→NO_WORK, ALARM→FAULT, etc. Operator override requires a separate dashboard input flow wired back to the database. Classification logic is split across multiple nodes.
fn-uns: uns-stoppage
Single Node.js function that auto-classifies stoppages from the uns_state table and provides a POST endpoint for operator overrides. All classification logic in one file. The mapping is a simple object — easy to read, easy to change, easy to review.
KPI Computation
Node-RED
Multiple function nodes with embedded SQL queries, each computing one metric. Results wired to dashboard gauges. Adding a new KPI means adding more nodes and wiring. The SQL is hidden inside node configs — invisible unless you click into each one.
fn-uns: uns-kpi
One Go function (250 lines) that computes all KPIs in a single HTTP request: utilisation, availability, throughput, MTBF, MTTR, stoppage pareto. Filterable by machine, area, and time range. Returns structured JSON. All SQL visible in one file.
Dashboards
Node-RED Dashboard
Built-in dashboard nodes — gauges, charts, buttons. Quick to set up but limited in capability. Dashboard layout is part of the flow — changes to the dashboard risk breaking the data flow. Not version-controlled separately.
fn-uns: Grafana
5 Grafana dashboards querying PostgreSQL directly with SQL. Professional-grade visualisation with time-series, state timelines, pareto charts. Dashboard JSON is version-controlled. Dashboards are completely decoupled from the data pipeline.
The Scaling Story
The real difference between flow-based and function-based approaches becomes clear when you scale. Here's what happens at each stage:
1 Machine → 10 Machines
| Aspect | Node-RED | fn-uns |
|---|---|---|
| Effort | Duplicate nodes or use wildcard subscriptions. Manageable. | No change needed — wildcard subscription and topic parsing handle it automatically. |
| Complexity | Flow grows but stays readable. 30–50 nodes. | Same 12 functions. Zero additional complexity. |
| Verdict | Both approaches work fine at this scale. | Both approaches work fine at this scale. |
10 Machines → 100 Machines
| Aspect | Node-RED | fn-uns |
|---|---|---|
| Effort | Flows need restructuring. Multiple tabs. Performance tuning. The single Node.js process starts to strain under message volume. | No change needed. Valkey handles the cache volume. PostgreSQL handles the write volume. Functions are stateless. |
| Complexity | 200+ nodes. Multiple tabs. Hard to follow data paths. Context variables proliferate. | Same 12 functions. Topic parsing extracts machine identity automatically. |
| Verdict | Manageable but painful. You're spending time on flow management, not on business logic. | No additional work. The architecture was designed for this. |
1 Site → 5 Sites
| Aspect | Node-RED | fn-uns |
|---|---|---|
| Deployment | Export flow JSON → import at each site → manually edit broker addresses, machine names, database credentials. Repeat for every update. | git clone at each site. Site-specific config in .env files. Updates via git pull. |
| Consistency | Each site drifts. Local modifications accumulate. No way to verify all sites run the same version. | Git ensures every site runs the same code. git log shows exactly what version each site is on. |
| Updates | Manual process per site. High risk of human error. No rollback. | git pull && docker compose up -d at each site. Rollback with git revert. |
| Verdict | This is where flow-based approaches break down. Multi-site management becomes a full-time job. | Multi-site is just git operations. The same workflow your IT team already uses for every other system. |
Manufacturing Engineer
At one site with a few machines, Node-RED is your friend. But when the plant manager says "roll this out to all our sites," you need something that scales without requiring you to manually replicate and maintain flows at each location. fn-uns gives you that — the same logic, deployed consistently, everywhere.
Developer
Multi-site deployment with Node-RED means building custom tooling to export, transform, and import flows — essentially building a deployment pipeline for a tool that wasn't designed for one. With fn-uns, you use git and Docker — tools you already know, with ecosystems you already trust.
IT Engineer
Your change management process requires audit trails, approval workflows, and rollback procedures. Git gives you all three out of the box. Node-RED's "click Deploy" doesn't fit into any enterprise change management framework. fn-uns deployments are just git operations — they slot into your existing ITIL processes.
Which Approach Should You Use?
This isn't a binary choice. The right tool depends on where you are in your UNS journey.
Use Node-RED When:
- ✓ You're exploring whether a UNS makes sense for your operation
- ✓ You need to prove the concept to stakeholders quickly
- ✓ You're working with a few machines at a single site
- ✓ The team is automation-focused rather than software-focused
- ✓ You need rapid iteration — trying different approaches daily
- ✓ It's a personal project or a small-team experiment
Use fn-uns + GitOps When:
- ✓ The UNS is becoming production infrastructure that the business depends on
- ✓ You need version control, code review, and audit trails
- ✓ Multiple people need to work on the system simultaneously
- ✓ You're deploying across multiple sites and need consistency
- ✓ Failure isolation matters — one bug shouldn't take down the whole pipeline
- ✓ You need safe rollbacks — the ability to undo a change instantly
- ✓ Your IT team requires change management processes
- ✓ You want to scale without scaling complexity
The Recommended Path
The Bottom Line
Node-RED is an excellent experimentation tool. Use it to prove your UNS concept, validate the data flow, and demonstrate business value. It's the fastest path from "idea" to "working demo."
But when your UNS becomes production infrastructure — when the business depends on it, when multiple people maintain it, when it needs to run reliably across multiple sites — you need the things that flow-based programming can't give you: version control, code review, failure isolation, automated testing, and safe rollbacks.
That's what fn-uns and GitOps provide. Not a different way to do the same thing — a better foundation for the same logic you already proved works.
Guide Version: 1.0 · Applies To: fn-uns pipeline, Node-RED comparison
Last updated March 2026.