Go-RED

module
v0.0.0-...-c0a0e91 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 21, 2026 License: MIT

README

Go-RED

A Node-RED-style flow editor and runtime in a single Go binary: wire nodes together in the browser, deploy, and watch messages flow. The editor is built into the binary, flows are JSON files on disk, and Node-RED flows.json exports import directly.

Go-RED editor, dark theme

60-second quickstart

Release binary (Linux, macOS, Windows; amd64 and arm64):

# pick the archive for your platform on https://github.com/GrimbiXcode/Go-RED/releases
tar -xzf go-red_*_linux_amd64.tar.gz
./go-red

Docker:

docker run -p 8080:8080 -v go-red-data:/app/data ghcr.io/grimbixcode/go-red:latest

From source (Go 1.25+, Node 22):

git clone https://github.com/GrimbiXcode/Go-RED.git && cd Go-RED
make start          # checks your tools, installs, builds and runs on :8080

make help lists every other command; make start PORT=9090 picks another port.

Open http://localhost:8080, drag an Inject, a Function and a Debug node onto the canvas, wire them, press Deploy: messages show up in the Debug tab within a second. Flows are saved as you edit; deploy is what starts them.

What is in the box

  • Editor: undo/redo, copy/paste across flows, rubber-band selection, snap to grid, align/distribute, auto-layout, context menus, quick-add by double-click, drop a node onto a wire to insert it, keyboard shortcuts (? lists them), tabs with drag ordering, light and dark theme, English and German.
  • Nodes (47, all compiled in): inject, debug, function (JavaScript), switch, change, template, delay, trigger, range, filter (rbe), exec; split/join/batch/sort, link in/out, junction, catch/status/complete, comment; http in/request/response, tcp, udp, mqtt, websocket, http proxy, tls config; json/xml/yaml/csv/html parsers; file, file in, watch.
  • Node-RED import and export: flows.json in (one flow per tab, wires and properties mapped, unsupported types reported), flows.json out.
  • Runtime feedback: node status on the canvas, per-node counters, a live debug sidebar with history for late joiners.
  • Operations: one binary, JSON flow files with backups and quarantine, optional access token, origin policy, rate limits, GET /api/health, GET /api/version, Prometheus GET /metrics, configuration by flags, GORED_* environment or a YAML file.
  • Measured performance: see docs/PERFORMANCE.md (on 4 vCPUs a function-node chain moves about 90 000 messages per second).

Compared with Node-RED

Go-RED Node-RED
Runtime one static Go binary, no Node.js at run time Node.js
Editor React, embedded in the binary bundled
Built-in nodes 47 core-equivalent nodes (see above) core palette
Function node JavaScript (goja): msg, flow/global context, no npm modules JavaScript (V8) with npm modules
Extra nodes Go packages compiled in (docs/NODE_DEVELOPMENT.md) npm packages installed at run time
Import/export Go-RED JSON and Node-RED flows.json flows.json
Subflows, groups not yet (skipped on import with a warning) yes
Dashboard no via community nodes
Context flow and global in memory memory, plus persistent stores
Concurrency per-flow queue and bounded goroutines, every node cancellable single event loop
Auth bearer token, origin policy, rate limits admin auth with users and roles
Metrics Prometheus /metrics built in via plugin
Persistence one JSON file per flow, versioned, with backups flows.json

Configuration

Every setting has a flag, a GORED_* environment variable and a key in an optional YAML file (-config go-red.yaml or GORED_CONFIG); flags win over the environment, which wins over the file.

Flag Env Default Meaning
-port GORED_PORT 8080 HTTP port
-data-dir GORED_DATA_DIR data flows, backups, quarantine
-auth-token GORED_AUTH_TOKEN – bearer token for the API, the WebSocket and /metrics (≥ 16 chars of A-Z a-z 0-9 . _ ~ -); the editor asks for it once
-allowed-origins GORED_ALLOWED_ORIGINS – extra browser origins (scheme://host[:port], comma-separated, or *); the editor's own origin is always allowed
-rate-limit GORED_RATE_LIMIT 60 import/deploy requests per client and minute (0 disables)
-max-inflight GORED_MAX_INFLIGHT 1024 concurrent node executions per flow (a flow's maxConcurrency overrides it)
-max-messages GORED_MAX_MESSAGES 1000 message queue size per flow
-message-log GORED_MESSAGE_LOG 0 routed messages kept for GET /api/messages
-backup-keep / -backup-interval GORED_BACKUP_KEEP / GORED_BACKUP_INTERVAL 5 / 10m backups per flow file and the minimum time between two
-web-dir GORED_WEB_DIR embedded serve the editor from a directory instead of the embedded build (development)
-log-level GORED_LOG_LEVEL info debug, info, warn, error
# go-red.yaml
port: 8080
authToken: change-me-to-something-long
allowedOrigins: [https://dashboard.example]
rateLimit: 30

The server refuses cross-site browser requests unless their origin is allowed. GET /api/health and GET /api/version are always public. Everything on the wire is documented in docs/PROTOCOL.md.

Documentation

Document What it covers
docs/PROTOCOL.md REST and WebSocket contract, node schemas, auth, configuration, persistence format, Node-RED mapping
docs/ARCHITECTURE.md components, dispatch, flow lifecycle, event flow, the editor's stores
docs/NODE_DEVELOPMENT.md writing a node in Go: interfaces, config schema, shared helpers, cancellation
docs/PERFORMANCE.md benchmark results and how to read them
docs/NEXT_LEVEL_PLAN.md the audit and the seven phases that produced the current state

Development

make setup                      # once: checks Go and Node, installs all dependencies
make dev                        # API on :8080 and the editor with hot reload on :5173; Ctrl+C stops both
make check                      # everything CI runs: gofmt, vet, race tests, generated types, web checks
make e2e                        # Playwright against the real server
go test ./internal/engine -run '^$' -bench . -benchtime 20000x
make generate-types             # after changing Go DTOs or WebSocket message types

The repository layout, the rules every change follows and the per-directory guides are in AGENTS.md. Releases are cut by tagging vX.Y.Z (GoReleaser builds the binaries and the multi-arch image, see .goreleaser.yaml).

Contributing

Conventional commits, tests with every change, make check green before a pull request. Bug reports and node contributions are welcome.

License

MIT, see LICENSE.

Directories

Path Synopsis
cmd
gentypes command
Command gentypes generates the canonical TypeScript wire types (web/src/types/generated.ts) from the Go structs that define the frontend/backend contract: internal/dto, internal/registry, and cmd/go-red/websocket.
Command gentypes generates the canonical TypeScript wire types (web/src/types/generated.ts) from the Go structs that define the frontend/backend contract: internal/dto, internal/registry, and cmd/go-red/websocket.
go-red command
Package main is the entry point for the Go—RED application.
Package main is the entry point for the Go—RED application.
go-red/websocket
Package websocket provides WebSocket communication for Go-RED.
Package websocket provides WebSocket communication for Go-RED.
internal
dto
Package dto defines the canonical wire format shared between the Go backend and the TypeScript frontend for REST and WebSocket payloads.
Package dto defines the canonical wire format shared between the Go backend and the TypeScript frontend for REST and WebSocket payloads.
engine
Package engine provides the core flow execution engine for Go—RED.
Package engine provides the core flow execution engine for Go—RED.
nodered
Package nodered converts between Node-RED's flows.json export (a flat array of nodes with "wires") and Go-RED flows, so flows built in Node-RED can be brought over and Go-RED flows can be handed back.
Package nodered converts between Node-RED's flows.json export (a flat array of nodes with "wires") and Go-RED flows, so flows built in Node-RED can be brought over and Go-RED flows can be handed back.
nodes/base
Package base holds the small helpers every node package under internal/nodes used to hand-roll for itself: reading JSON-decoded configuration maps with defaults (Config, Decode), coercing message values (ToFloat, ToString, ToBytes, CloneMap, ...), converting typedvalue.Value/PropertyRef to and from their config-map form, and extracting the context.Context / registry.NodeRuntime the engine passes to Execute as an interface{} (Context, Runtime, Resolvers).
Package base holds the small helpers every node package under internal/nodes used to hand-roll for itself: reading JSON-decoded configuration maps with defaults (Config, Decode), coercing message values (ToFloat, ToString, ToBytes, CloneMap, ...), converting typedvalue.Value/PropertyRef to and from their config-map form, and extracting the context.Context / registry.NodeRuntime the engine passes to Execute as an interface{} (Context, Runtime, Resolvers).
nodes/batch
Package batch provides the Batch node implementation.
Package batch provides the Batch node implementation.
nodes/catch
Package catch provides the Catch node implementation.
Package catch provides the Catch node implementation.
nodes/change
Package change provides the Change node implementation.
Package change provides the Change node implementation.
nodes/comment
Package comment provides the Comment node implementation.
Package comment provides the Comment node implementation.
nodes/complete
Package complete provides the Complete node implementation.
Package complete provides the Complete node implementation.
nodes/csvnode
Package csvnode provides the CSV node implementation (Node-RED type ID "csv" - named csvnode here to avoid shadowing the imported encoding/csv package within this file).
Package csvnode provides the CSV node implementation (Node-RED type ID "csv" - named csvnode here to avoid shadowing the imported encoding/csv package within this file).
nodes/debug
Package debug provides the Debug node implementation.
Package debug provides the Debug node implementation.
nodes/delay
Package delay provides the Delay node implementation.
Package delay provides the Delay node implementation.
nodes/execnode
Package execnode provides the Exec node implementation (Node-RED type ID "exec" - named execnode here to avoid shadowing the imported stdlib os/exec package within this file).
Package execnode provides the Exec node implementation (Node-RED type ID "exec" - named execnode here to avoid shadowing the imported stdlib os/exec package within this file).
nodes/file
Package file provides the File node implementation (Node-RED's "file" node - writes, appends to, or deletes a file).
Package file provides the File node implementation (Node-RED's "file" node - writes, appends to, or deletes a file).
nodes/filein
Package filein provides the "File in" node implementation (Node-RED type ID "file in" - reads a file into the message).
Package filein provides the "File in" node implementation (Node-RED type ID "file in" - reads a file into the message).
nodes/function
Package function provides the Function node implementation.
Package function provides the Function node implementation.
nodes/htmlnode
Package htmlnode provides the HTML node implementation (Node-RED type ID "html" - named htmlnode here to avoid shadowing the imported golang.org/x/net/html package within this file).
Package htmlnode provides the HTML node implementation (Node-RED type ID "html" - named htmlnode here to avoid shadowing the imported golang.org/x/net/html package within this file).
nodes/httpin
Package httpin provides the "http in" node implementation - registers a (method, path) route on a shared HTTP listener and emits one message per matching incoming request, pairing it with a *ResponseHandle so a downstream "http response" node (internal/nodes/httpresponse) can complete it.
Package httpin provides the "http in" node implementation - registers a (method, path) route on a shared HTTP listener and emits one message per matching incoming request, pairing it with a *ResponseHandle so a downstream "http response" node (internal/nodes/httpresponse) can complete it.
nodes/httpproxy
Package httpproxy provides the "http proxy" config node - a reusable outbound HTTP/HTTPS proxy configuration referenced by ID from other nodes (http request), rather than being wired into a flow itself (see docs/NODE_PALETTE_PLAN.md, Phase 6's config-node concept).
Package httpproxy provides the "http proxy" config node - a reusable outbound HTTP/HTTPS proxy configuration referenced by ID from other nodes (http request), rather than being wired into a flow itself (see docs/NODE_PALETTE_PLAN.md, Phase 6's config-node concept).
nodes/httprequest
Package httprequest provides the "http request" node implementation - issues an outgoing HTTP request and returns the response.
Package httprequest provides the "http request" node implementation - issues an outgoing HTTP request and returns the response.
nodes/httpresponse
Package httpresponse provides the "http response" node implementation - completes the in-flight HTTP request an upstream "http in" node (internal/nodes/httpin) paired with the message via a *httpin.ResponseHandle stored under httpin.KeyResponseHandle.
Package httpresponse provides the "http response" node implementation - completes the in-flight HTTP request an upstream "http in" node (internal/nodes/httpin) paired with the message via a *httpin.ResponseHandle stored under httpin.KeyResponseHandle.
nodes/inject
Package inject provides the Inject node implementation.
Package inject provides the Inject node implementation.
nodes/join
Package join provides the Join node implementation.
Package join provides the Join node implementation.
nodes/jsonnode
Package jsonnode provides the JSON node implementation (Node-RED type ID "json" - named jsonnode here to avoid shadowing the imported encoding/json package within this file).
Package jsonnode provides the JSON node implementation (Node-RED type ID "json" - named jsonnode here to avoid shadowing the imported encoding/json package within this file).
nodes/junction
Package junction provides the Junction node implementation.
Package junction provides the Junction node implementation.
nodes/linkin
Package linkin provides the Link In node implementation.
Package linkin provides the Link In node implementation.
nodes/linkout
Package linkout provides the Link Out node implementation.
Package linkout provides the Link Out node implementation.
nodes/mqttbroker
Package mqttbroker provides the "mqtt-broker" config node - a single shared paho.mqtt.golang connection, referenced by ID from mqtt in/mqtt out nodes rather than each opening its own connection (see docs/NODE_PALETTE_PLAN.md, Phase 6's config-node concept).
Package mqttbroker provides the "mqtt-broker" config node - a single shared paho.mqtt.golang connection, referenced by ID from mqtt in/mqtt out nodes rather than each opening its own connection (see docs/NODE_PALETTE_PLAN.md, Phase 6's config-node concept).
nodes/mqttin
Package mqttin provides the "mqtt in" node implementation - subscribes to a topic on a shared mqtt-broker config node (internal/nodes/mqttbroker) and emits one message per received publish.
Package mqttin provides the "mqtt in" node implementation - subscribes to a topic on a shared mqtt-broker config node (internal/nodes/mqttbroker) and emits one message per received publish.
nodes/mqttout
Package mqttout provides the "mqtt out" node implementation - publishes msg.payload to a topic on a shared mqtt-broker config node (internal/nodes/mqttbroker).
Package mqttout provides the "mqtt out" node implementation - publishes msg.payload to a topic on a shared mqtt-broker config node (internal/nodes/mqttbroker).
nodes/rangenode
Package rangenode provides the Range node implementation (Node-RED type ID "range" - named rangenode here since "range" is a Go keyword and can't be a package name).
Package rangenode provides the Range node implementation (Node-RED type ID "range" - named rangenode here since "range" is a Go keyword and can't be a package name).
nodes/rbe
Package rbe provides the RBE ("report by exception") / Filter node implementation.
Package rbe provides the RBE ("report by exception") / Filter node implementation.
nodes/sortnode
Package sortnode provides the Sort node implementation (Node-RED type ID "sort" - named sortnode here to avoid shadowing the imported stdlib sort package within this file).
Package sortnode provides the Sort node implementation (Node-RED type ID "sort" - named sortnode here to avoid shadowing the imported stdlib sort package within this file).
nodes/split
Package split provides the Split node implementation.
Package split provides the Split node implementation.
nodes/status
Package status provides the Status node implementation.
Package status provides the Status node implementation.
nodes/switchnode
Package switchnode provides the Switch node implementation (Node-RED type ID "switch" - named switchnode here since "switch" is a Go keyword and can't be a package name).
Package switchnode provides the Switch node implementation (Node-RED type ID "switch" - named switchnode here since "switch" is a Go keyword and can't be a package name).
nodes/tcpin
Package tcpin provides the "tcp in" node implementation - either listens for TCP connections (Server mode) or connects out to a remote host (client mode), emitting one message per line or per raw read from every connection.
Package tcpin provides the "tcp in" node implementation - either listens for TCP connections (Server mode) or connects out to a remote host (client mode), emitting one message per line or per raw read from every connection.
nodes/tcpout
Package tcpout provides the "tcp out" node implementation - connects out to a remote host:port and writes msg.payload, once per message (a new connection per Execute call, not a persistent one reused across messages).
Package tcpout provides the "tcp out" node implementation - connects out to a remote host:port and writes msg.payload, once per message (a new connection per Execute call, not a persistent one reused across messages).
nodes/tcprequest
Package tcprequest provides the "tcp request" node implementation - connects out, writes msg.payload, half-closes the write side (signaling EOF to the peer, the common TCP request/response idiom), and returns whatever the peer sends back before closing its own side (or before TimeoutMs/maxReplyBytes is hit).
Package tcprequest provides the "tcp request" node implementation - connects out, writes msg.payload, half-closes the write side (signaling EOF to the peer, the common TCP request/response idiom), and returns whatever the peer sends back before closing its own side (or before TimeoutMs/maxReplyBytes is hit).
nodes/template
Package template provides the Template node implementation.
Package template provides the Template node implementation.
nodes/tlsconfig
Package tlsconfig provides the "tls-config" config node - a reusable TLS client/server certificate configuration referenced by ID from other nodes (http request, mqtt-broker, websocket-client), rather than being wired into a flow itself (see docs/NODE_PALETTE_PLAN.md, Phase 6's config-node concept).
Package tlsconfig provides the "tls-config" config node - a reusable TLS client/server certificate configuration referenced by ID from other nodes (http request, mqtt-broker, websocket-client), rather than being wired into a flow itself (see docs/NODE_PALETTE_PLAN.md, Phase 6's config-node concept).
nodes/trigger
Package trigger provides the Trigger node implementation.
Package trigger provides the Trigger node implementation.
nodes/udpin
Package udpin provides the "udp in" node implementation - listens for UDP datagrams on Port and emits one message per received datagram.
Package udpin provides the "udp in" node implementation - listens for UDP datagrams on Port and emits one message per received datagram.
nodes/udpout
Package udpout provides the "udp out" node implementation - sends msg.payload as a single UDP datagram to Host:Port.
Package udpout provides the "udp out" node implementation - sends msg.payload as a single UDP datagram to Host:Port.
nodes/watch
Package watch provides the Watch node implementation - a registry.EmittingNode with no input port that emits a message whenever one of its configured files or directories changes.
Package watch provides the Watch node implementation - a registry.EmittingNode with no input port that emits a message whenever one of its configured files or directories changes.
nodes/websocketclient
Package websocketclient provides the "websocket-client" config node - an outgoing WebSocket connection to a remote URL, referenced by ID from websocket in/websocket out (see docs/NODE_PALETTE_PLAN.md, Phase 6's config-node concept).
Package websocketclient provides the "websocket-client" config node - an outgoing WebSocket connection to a remote URL, referenced by ID from websocket in/websocket out (see docs/NODE_PALETTE_PLAN.md, Phase 6's config-node concept).
nodes/websocketin
Package websocketin provides the "websocket in" node implementation - emits one message per message received on a shared websocket-listener or websocket-client config node (internal/nodes/websocketlistener, internal/nodes/websocketclient - either works, since both expose the same OnMessage method this node type-asserts for).
Package websocketin provides the "websocket in" node implementation - emits one message per message received on a shared websocket-listener or websocket-client config node (internal/nodes/websocketlistener, internal/nodes/websocketclient - either works, since both expose the same OnMessage method this node type-asserts for).
nodes/websocketlistener
Package websocketlistener provides the "websocket-listener" config node - a server-side WebSocket endpoint mounted on the shared "http in" listener (internal/nodes/httpin), referenced by ID from websocket in/websocket out (see docs/NODE_PALETTE_PLAN.md, Phase 6's config-node concept).
Package websocketlistener provides the "websocket-listener" config node - a server-side WebSocket endpoint mounted on the shared "http in" listener (internal/nodes/httpin), referenced by ID from websocket in/websocket out (see docs/NODE_PALETTE_PLAN.md, Phase 6's config-node concept).
nodes/websocketout
Package websocketout provides the "websocket out" node implementation - sends msg.payload through a shared websocket-listener or websocket-client config node (internal/nodes/websocketlistener, internal/nodes/websocketclient).
Package websocketout provides the "websocket out" node implementation - sends msg.payload through a shared websocket-listener or websocket-client config node (internal/nodes/websocketlistener, internal/nodes/websocketclient).
nodes/xmlnode
Package xmlnode provides the XML node implementation (Node-RED type ID "xml" - named xmlnode here to avoid shadowing the imported encoding/xml package within this file).
Package xmlnode provides the XML node implementation (Node-RED type ID "xml" - named xmlnode here to avoid shadowing the imported encoding/xml package within this file).
nodes/yamlnode
Package yamlnode provides the YAML node implementation (Node-RED type ID "yaml" - named yamlnode here to avoid shadowing the imported yaml.v3 package within this file).
Package yamlnode provides the YAML node implementation (Node-RED type ID "yaml" - named yamlnode here to avoid shadowing the imported yaml.v3 package within this file).
registry
Package registry manages all available node types and their factories.
Package registry manages all available node types and their factories.
state
Package state provides persistence for flows and configurations.
Package state provides persistence for flows and configurations.
typedvalue
Package typedvalue resolves Node-RED-style "typed input" values: a (type, value) pair such as {"str", "hello"} or {"msg", "payload.count"} that a node's configuration uses wherever Node-RED lets a user pick between a literal, a message property, or flow/global context in the editor (the widget backing Switch's rules, Change's set/to, Template's fields, ...).
Package typedvalue resolves Node-RED-style "typed input" values: a (type, value) pair such as {"str", "hello"} or {"msg", "payload.count"} that a node's configuration uses wherever Node-RED lets a user pick between a literal, a message property, or flow/global context in the editor (the widget backing Switch's rules, Change's set/to, Template's fields, ...).
webui
Package webui carries the built editor inside the server binary.
Package webui carries the built editor inside the server binary.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL