> For the complete documentation index, see [llms.txt](https://docs.cybus.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.cybus.io/2-4-2/guides/migration/migrating-from-node-red.md).

# Migrating from Node-RED

This guide shows you how to migrate industrial Node-RED flows to Connectware by exporting the flows as JSON and translating the connectivity portion into a [service commissioning file](/2-4-2/data-flows/service-commissioning-files.md). Node-RED is widely used as a low-cost glue layer that reads PLCs through contrib nodes and publishes to MQTT. Those flows translate well, because the entire flow configuration is a single, well-defined JSON document. In more detail, the following topics are covered:

* Understanding how Node-RED concepts map to Connectware resources
* Exporting flows from the editor, the flow file, or the Admin API
* Translating the flows into a service commissioning file with an AI assistant
* Deciding what happens to function nodes and other logic
* Verifying the migrated data points in the [Data Explorer](/2-4-2/monitoring/data-explorer.md)

A complete worked example, from flow export to service commissioning file, is available at the end of this guide.

## Prerequisites

To follow this guide, you will need the following:

* A running instance of Cybus Connectware with licenses for the connectors that replace your contrib nodes.
* Access to the Node-RED editor, the flow file on disk, or the Admin API. The export format is the same across Node-RED 3.x and 4.x.
* Network access from Connectware to the devices that Node-RED currently polls.
* An AI assistant to translate the export. Any capable large language model (LLM) works. [Cybus Connectware GPT](/2-4-2/tools/cybus-connectware-gpt.md) is a ChatGPT assistant that already knows the service commissioning file format.
* Basic knowledge of the Connectware [services](/2-4-2/data-flows/services.md) concept (for example, [service commissioning files](/2-4-2/data-flows/service-commissioning-files.md), [connections](/2-4-2/data-flows/service-commissioning-files/resources/cybus-connection.md), and [endpoints](/2-4-2/data-flows/service-commissioning-files/resources/cybus-endpoint.md)).

## How Node-RED Concepts Map to Connectware

A Node-RED flow export is a flat JSON array of node objects. Nodes that talk to devices reference a configuration node by ID: the configuration node holds the connection settings, and the flow nodes hold the addresses and polling rates. Connectware separates the same concerns in resources of a service commissioning file:

| Node-RED concept                                                      | Connectware resource                                                                                                                                              | Notes                                                                                                                                |
| --------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| Configuration node (`modbus-client`, `s7 endpoint`, `OpcUa-Endpoint`) | [Cybus::Connection](/2-4-2/data-flows/service-commissioning-files/resources/cybus-connection.md)                                                                  | Holds host, port, and protocol-specific settings. One connection per configuration node.                                             |
| Read and poll nodes (`modbus-read`, `s7 in`, `OpcUa-Client`)          | [Cybus::Endpoint](/2-4-2/data-flows/service-commissioning-files/resources/cybus-endpoint.md)                                                                      | Address, quantity, and poll rate become the endpoint properties. The `s7 endpoint` variable table maps one-to-one to S7 endpoints.   |
| `mqtt out` node topic                                                 | [Cybus::Mapping](/2-4-2/data-flows/service-commissioning-files/resources/cybus-mapping.md)                                                                        | The topic can be reused verbatim on the integrated Connectware broker.                                                               |
| `mqtt-broker` configuration node                                      | Integrated Connectware broker                                                                                                                                     | External brokers that must keep receiving data become [MQTT connector](/2-4-2/connectors/enterprise-connectors/mqtt.md) connections. |
| Simple `function` nodes                                               | [Rule Engine](/2-4-2/data-flows/rule-engine.md)                                                                                                                   | Pure payload reshaping and scaling translate to JSONata `transform` rules.                                                           |
| Complex flows and logic                                               | [Node-RED Workbench](/2-4-2/data-flows/node-red-workbench.md) or a [Cybus::Container](/2-4-2/data-flows/service-commissioning-files/resources/cybus-container.md) | Flows import into the Workbench largely unchanged for prototyping; production Node-RED runs as a containerized service.              |

### Mapping Contrib Nodes to Connectors

The most common industrial contrib node families and their Connectware counterparts:

| Contrib package           | Configuration node | Connectware connector                                                                       |
| ------------------------- | ------------------ | ------------------------------------------------------------------------------------------- |
| `node-red-contrib-modbus` | `modbus-client`    | [Modbus/TCP](/2-4-2/connectors/shop-floor-connectors/modbus-tcp.md)                         |
| `node-red-contrib-s7`     | `s7 endpoint`      | [Siemens SIMATIC S7](/2-4-2/connectors/shop-floor-connectors/siemens-simatic-s7.md)         |
| `node-red-contrib-opcua`  | `OpcUa-Endpoint`   | [OPC UA Client](/2-4-2/connectors/shop-floor-connectors/opc-ua/opc-ua-client.md)            |
| Core MQTT nodes           | `mqtt-broker`      | Integrated broker, or the [MQTT connector](/2-4-2/connectors/enterprise-connectors/mqtt.md) |
| Core HTTP request node    | —                  | [HTTP/REST](/2-4-2/connectors/enterprise-connectors/http-rest.md)                           |

### What Does Not Migrate to Native Connectors

Node-RED is a general-purpose programming environment, so only the connectivity portion translates mechanically:

| Node-RED feature                             | Connectware approach                                                                                                                                                                 |
| -------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `function` nodes with arbitrary JavaScript   | Simple reshaping becomes a JSONata `transform` rule. Everything else moves to the [Node-RED Workbench](/2-4-2/data-flows/node-red-workbench.md) or a containerized Node-RED service. |
| Dashboards                                   | Out of scope. Visualization consumes data from Connectware topics instead.                                                                                                           |
| `http in` / `http response` endpoints        | Re-implement with the [HTTP Server](/2-4-2/connectors/servers/http-server.md), or keep them in a Node-RED instance.                                                                  |
| Dynamic-address nodes (`modbus-flex-getter`) | Addresses computed at runtime cannot be translated statically. Redesign as fixed endpoints or keep the flow in Node-RED.                                                             |
| Context storage, timers, stateful logic      | Keep in Node-RED (Workbench or container) and exchange data with Connectware over MQTT.                                                                                              |

The Node-RED Workbench in Connectware is intended for prototyping and testing. For production workloads, run Node-RED as a dedicated service with a [Cybus::Container](/2-4-2/data-flows/service-commissioning-files/resources/cybus-container.md) resource, connected to the Connectware broker.

## Exporting the Node-RED Flows

Any of the following gives you the same flat JSON array:

* **Editor:** Open the main menu and select **Export** (or press Ctrl+E / Cmd+E), select **all flows**, choose the formatted JSON, and download or copy it.
* **Flow file:** The runtime stores all flows in the `flows.json` file in the Node-RED user directory, `~/.node-red` by default. Installations older than Node-RED 2.0 use a `flows_<hostname>.json` file name.
* **Admin API:** `GET http://${NODE_RED_HOST}:1880/flows` returns the active flow configuration (with a bearer token if `adminAuth` is enabled).

{% hint style="warning" %}
Credentials never appear in flow exports: Node-RED stores them encrypted in a separate `flows_cred.json` file. Collect broker and PLC credentials separately and pass them into the service as parameters. Before you paste an export into an AI tool, also check `function` node code for hardcoded secrets, and check the data privacy terms of the tool you use. See also the privacy notes for [Cybus Connectware GPT](/2-4-2/tools/cybus-connectware-gpt.md#data-privacy).
{% endhint %}

## Translating the Flows with an AI Assistant

Copy the following prompt and attach the flow export:

{% code title="AI translation prompt" lineNumbers="true" expandable="true" %}

```
You are translating a Node-RED flow export (a flat JSON array of node
objects) into a Cybus Connectware service commissioning file (YAML). Produce
one complete, valid service commissioning file with description, metadata,
parameters, definitions, and resources.

Structural rules:
- Configuration nodes (no "x"/"y"/"wires" properties) hold connection
  settings and are referenced by ID from flow nodes ("server", "endpoint",
  "broker" properties). Create one Cybus::Connection per protocol
  configuration node that is actually referenced.
- Skip "tab" and "junction" nodes. Follow "wires" arrays to understand
  which read node feeds which mqtt out node.
- Create one Cybus::Endpoint per read/poll definition, referencing its
  connection with !ref.
- Topics of "mqtt out" nodes are reused verbatim as Cybus::Mapping publish
  topics on the integrated Connectware broker. The "mqtt-broker"
  configuration node itself needs no counterpart unless an external broker
  must keep receiving data; in that case create an Mqtt connection and flag
  it.
- "function" nodes between a read node and an mqtt out node: if the code
  only reshapes or scales the payload, translate it to a JSONata transform
  rule on the mapping entry and include the original JavaScript as a
  comment. Otherwise flag the flow for the Node-RED Workbench.
- Define hosts and credentials as parameters, never hardcoded. Credentials
  are not part of the export; list every configuration node that needs
  credentials re-entered.

Rules for node-red-contrib-modbus (protocol: Modbus):
- "modbus-client" configuration nodes: use "tcpHost" and "tcpPort".
  Flag "clienttype": "serial" nodes: Connectware Modbus supports TCP.
- "modbus-read" nodes: "dataType" encodes the function code (Coil -> fc 1,
  Input -> fc 2, HoldingRegister -> fc 3, InputRegister -> fc 4), "adr" is
  the 0-based address, "quantity" the register count, "unitid" the unit ID.
  Convert "rate" + "rateUnit" (ms/s/m/h) to a millisecond interval.
- The Modbus payload is a value array; the Connectware dataType must be
  inferred from how downstream nodes use the payload. Default 16-bit
  registers to int16BE with length 1 and flag every inference.
- Flag "modbus-getter" (triggered reads) and "modbus-flex-*" nodes
  (runtime-computed addresses) for manual redesign.

Rules for node-red-contrib-s7 (protocol: S7):
- "s7 endpoint" configuration nodes: "address" (host), "port" (102),
  "rack", "slot", and "cycletime" (poll interval in ms, use as the
  connection pollInterval). The "vartable" array of {name, addr} entries
  is the tag list: create one endpoint per entry; the address syntax
  ("DB5,REAL0", "MB10") matches the Connectware S7 syntax closely. Verify
  data type letters and flag uncertain addresses.
- "s7 in" nodes with "diff": true publish on change only: add a Rule
  Engine cov rule with key "value" to those mapping entries.

Rules for node-red-contrib-opcua (protocol: Opcua):
- "OpcUa-Endpoint" configuration nodes: parse host and port from the
  "endpoint" URL, map "secpol"/"secmode" to securityPolicy and
  messageSecurityMode.
- NodeIds usually come from "OpcUa-Item" nodes ("item" property, for
  example "ns=2;s=Machine.Temperature") wired into the client, or from
  inject node topics. Collect them into endpoints. Flag flows where the
  NodeId is computed at runtime.

After the YAML, output a migration report: number of connections and
endpoints translated, every function node and its disposition (transform
rule or Workbench), all assumptions made, and every flagged item.

[Attach the flows.json export.]
```

{% endcode %}

## Reviewing the Generated Service Commissioning File

Work through this checklist before installing:

1. Validate the file structure. The [Cybus Connectware Extension for VS Code](/2-4-2/tools/cybus-connectware-extension-vs-code.md) validates service commissioning files against the official schemas as you edit.
2. Check every connection against its configuration node: host, port, rack and slot, and security settings.
3. Spot-check translated addresses and inferred Modbus data types against live values.
4. Review every generated JSONata transform against the original `function` node code.
5. Re-enter all credentials as parameters; they were not part of the export.
6. Compare the endpoint count against the migration report of the AI assistant.

## Installing the Service

1. Install the service commissioning file. See [Installing Services](/2-4-2/data-flows/services/managing/installing.md).
2. Enable the service. See [Enabling Services](/2-4-2/data-flows/services/managing/enabling.md).

**Result:** Connectware connects to the migrated devices directly and the connections reach the **Connected** state.

{% hint style="info" %}
For read-only validation, Connectware and Node-RED can usually poll the same device at the same time, which allows you to compare live values before you retire the flows. Check the connection limits of your devices first. Disable the migrated flows in Node-RED once the migration is verified.
{% endhint %}

## Verifying the Data

Open the [Data Explorer](/2-4-2/monitoring/data-explorer.md) and subscribe to the topics of the migrated service:

* Every migrated data point publishes on its topic with plausible values.
* Values match between Node-RED (for example, in a debug node) and Connectware.
* Payloads shaped by transform rules match what the original function nodes produced. Compare a sample message from each system side by side.
* Data arrives at the original poll rates.

## Worked Example

The following flow export reads two holding registers from a PLC every second, scales the first register in a function node, and publishes the result to MQTT. It contains a tab, three flow nodes, and two configuration nodes:

{% code title="flows.json" lineNumbers="true" expandable="true" %}

```json
[
  {
    "id": "9a4f2c1e8b3d5a70",
    "type": "tab",
    "label": "Line 1 - Filling Machine"
  },
  {
    "id": "5e8d3a129c7f4b06",
    "type": "modbus-read",
    "z": "9a4f2c1e8b3d5a70",
    "name": "Read fill level",
    "unitid": "1",
    "dataType": "HoldingRegister",
    "adr": "0",
    "quantity": "2",
    "rate": "1",
    "rateUnit": "s",
    "server": "c2b7e9d04a1f6835",
    "wires": [["7f1c6b3e9d2a4580"], []]
  },
  {
    "id": "7f1c6b3e9d2a4580",
    "type": "function",
    "z": "9a4f2c1e8b3d5a70",
    "name": "Scale to liters",
    "func": "msg.payload = { fillLevel: msg.payload[0] / 10 };\nreturn msg;",
    "outputs": 1,
    "wires": [["3d9e5f2a8c4b1670"]]
  },
  {
    "id": "3d9e5f2a8c4b1670",
    "type": "mqtt out",
    "z": "9a4f2c1e8b3d5a70",
    "name": "Publish fill level",
    "topic": "factory/line1/filling/fill-level",
    "qos": "1",
    "broker": "a8c5d2f17e9b3460",
    "wires": []
  },
  {
    "id": "c2b7e9d04a1f6835",
    "type": "modbus-client",
    "name": "Filling Machine PLC",
    "clienttype": "tcp",
    "tcpHost": "192.168.1.100",
    "tcpPort": "502",
    "unit_id": "1"
  },
  {
    "id": "a8c5d2f17e9b3460",
    "type": "mqtt-broker",
    "name": "Plant broker",
    "broker": "broker.example.com",
    "port": "8883",
    "usetls": true
  }
]
```

{% endcode %}

Applying the translation rules produces the following service commissioning file. The `modbus-client` node becomes a Modbus connection; the `modbus-read` node becomes a holding register endpoint at address 0 with a one-second interval; the function node only uses the first register, so the endpoint reads one register as `int16BE` and the scaling becomes a JSONata `transform` rule; and the MQTT topic is reused verbatim:

{% file src="/files/D5fIIephyVqGU7YSPowj" %}

{% code title="node-red-migration-example.yml" lineNumbers="true" expandable="true" %}

```yaml
description: >
  Service commissioning file migrated from the Node-RED flow
  "Line 1 - Filling Machine" (Example)

metadata:
  name: Node-RED Migration Example
  provider: cybus
  homepage: https://www.cybus.io
  version: 1.0.0

parameters:
  plcHost:
    description: Host of the modbus-client node "Filling Machine PLC"
    type: string
    default: 192.168.1.100

  plcPort:
    description: Port of the modbus-client node "Filling Machine PLC"
    type: integer
    default: 502

resources:
  # Configuration node "Filling Machine PLC" (modbus-client)
  fillingMachineConnection:
    type: Cybus::Connection
    properties:
      protocol: Modbus
      targetState: connected
      connection:
        host: !ref plcHost
        port: !ref plcPort

  # Node "Read fill level": HoldingRegister, adr 0, rate 1 s
  # The downstream function node only uses the first register.
  fillLevel:
    type: Cybus::Endpoint
    properties:
      protocol: Modbus
      connection: !ref fillingMachineConnection
      subscribe:
        fc: 3
        address: 0
        length: 1
        dataType: int16BE
        interval: 1000

  # Function node "Scale to liters" became a JSONata transform rule:
  # msg.payload = { fillLevel: msg.payload[0] / 10 }
  mapping:
    type: Cybus::Mapping
    properties:
      mappings:
        - subscribe:
            endpoint: !ref fillLevel
          publish:
            topic: factory/line1/filling/fill-level
          rules:
            - transform:
                expression: |
                  {
                    "timestamp": timestamp,
                    "fillLevel": value / 10
                  }
```

{% endcode %}

The `mqtt-broker` node needs no counterpart: consumers subscribe to the topic on the integrated Connectware broker. If the external broker at `broker.example.com` must keep receiving the data, add an [MQTT connector](/2-4-2/connectors/enterprise-connectors/mqtt.md) connection with a mapping.

For all Modbus connection and endpoint properties, see [Modbus Connection Properties](/2-4-2/connectors/shop-floor-connectors/modbus-tcp/modbusconnection.md) and [Modbus Endpoint Properties](/2-4-2/connectors/shop-floor-connectors/modbus-tcp/modbusendpoint.md). For the `transform` rule, see [Data Processing Rules](/2-4-2/data-flows/rule-engine/data-processing-rules.md).

{% hint style="info" %}
Disclaimer: Node-RED is a trademark of the OpenJS Foundation. Cybus is not affiliated with the OpenJS Foundation.
{% endhint %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.cybus.io/2-4-2/guides/migration/migrating-from-node-red.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
