Skip to main content

PyRED

A port of Node-RED 5.0.7 to Python.

The same editor, the same flow file, the same node set, the same HTTP admin API — with a Python runtime and nodes written in Python.

The PyRED editor

What "port" means here

Layer Origin
Editor client Node-RED source, vendored and built with the same pipeline
Node edit dialogs and message catalogues Node-RED source, adapted only where the runtime language shows through
HTTP admin API Re-implemented in Python, wire-compatible with the editor
Flow runtime, node registry, context, credentials, storage Re-implemented in Python
Projects (git-backed flows), multiplayer, palette catalogue Re-implemented in Python
Prometheus metrics endpoint and exporter nodes New; the nodes ported from node-red-contrib-prometheus-exporter
Core nodes Re-implemented in Python — all 50 types

The editor is not a reimplementation. It is Node-RED's own editor, talking to a Python implementation of the API it expects. Flows exported from Node-RED import into PyRED and back again: the flow file is the same JSON, and the credentials file uses the same encryption.

See docs/porting.md for the full correspondence.

Where it deliberately differs

Two things cannot be carried over one-to-one, because they are the JavaScript runtime:

  1. The Function node runs Python. The same three tabs (On Start, On Message, On Stop), the same node / flow / env objects, the same send and done semantics — but the body is Python:

    msg["payload"] = msg["payload"] * 2
    return msg
    

    The body is compiled into an async def, so await works directly. global is a Python keyword, so the global context object is global_.

  2. Packages come from PyPI. The Function node's Setup tab and the palette manager install Python distributions. A PyRED node package is an ordinary distribution that advertises a pyred.nodes entry point.

Installing

The distribution is pyflowred on PyPI — pyred was already taken there by an unrelated project. The import package, the command and the editor are all still PyRED.

pip install pyflowred     # or: uv pip install pyflowred
pyred                     # pyflowred runs the same thing

The wheel carries the built editor, so this needs Python and nothing else — no Node, no build step. The editor is then at http://127.0.0.1:1880/.

In a container

Two images, same application. Dockerfile installs the released package with uv and carries no build tooling; Dockerfile.source builds this checkout in three stages, Node included.

docker build -t pyred:0.1.0 .                        # released
docker build -f Dockerfile.source -t pyred:source .  # this checkout
docker run -d -p 1880:1880 -v pyred-data:/data pyred:0.1.0

Your own CA is a build argument or a mount, and reaches every library in the runtime. See docker/README.md.

Building it

Node.js is needed once, to build the editor. It is never needed at runtime.

npm install          # editor build dependencies
npm run build        # builds src/pyred/editor_client/public
uv build --wheel     # ~10 MB, py3-none-any

That build output is a git-ignored artifact, so the wheel has to pull it back in deliberately (tool.hatch.build.targets.wheel.artifacts). A build hook refuses to produce a wheel when the editor has not been built, because the failure mode otherwise is a package that installs, starts, and serves a blank page. The editor source is excluded from the wheel and kept in the sdist, where it can be rebuilt.

Working on it

npm install && npm run build
uv venv --python 3.13
uv pip install -e ".[dev]"
.venv/bin/pyred

Without adminAuth, anyone who can reach the editor can run arbitrary Python as the user running the process. See docs/operations.md.

Writing a node

def register(RED):
    class LowerCaseNode(RED.Node):
        def __init__(self, config):
            super().__init__(config)
            self.on("input", self._on_input)

        def _on_input(self, msg, send, done):
            msg["payload"] = msg["payload"].lower()
            send(msg)
            done()

    RED.nodes.register_type("lower-case", LowerCaseNode)

with the matching .html next to it, exactly as in Node-RED. A complete example package is in examples/pyred-node-lowercase; the details are in docs/writing-nodes.md.

Layout

src/pyred/
  util/            property expressions, JSONata, mustache, cloning, logging, i18n
  runtime/         flow engine, node registry, context, credentials, storage
  registry/        node discovery, loading, palette installation
  api/             HTTP admin API, editor routes, comms WebSocket (Starlette)
  metrics/         the Prometheus registry, runtime instrumentation, endpoint
  nodes/core/      the core node set: Python implementations + Node-RED dialogs
  editor_client/   the Node-RED editor, vendored and built
tools/
  editor-build/    the Node-RED editor build pipeline, re-pointed at this repo
  devserver.sh     start/stop a throwaway instance
  uicheck.py       load the editor in a real browser and report on it
  uiflow.py        deploy and run a flow through the editor, in a real browser
  uiprojects.py    commit a deploy through the project UI, in a real browser
  benchflows.py    seven benchmark flows, 82 nodes across 33 node types
  loadtest.py      drive them and sample the runtime's CPU, RSS and fds
  rawbaseline.py   a bare Starlette endpoint, to measure the runtime against
Dockerfile         the released package, installed with uv
Dockerfile.source  this checkout, editor and all
docker/            entrypoint, compose, CA drop-in
examples/          an example node package
docs/              porting notes, node authoring, operations, benchmarks
tests/             the test suite, including a browser test of the editor

Tests

.venv/bin/python -m pytest tests

The suite covers every node group against real sockets (including an in-process MQTT broker), the runtime (subflows, groups, context, credentials, deploy types), the admin API, projects against a real git binary, and — when Playwright is available — the actual editor in a headless browser: import a flow, press Deploy, open the Function node, click Inject, read the debug sidebar.

Licence

Apache-2.0, as Node-RED is. The vendored editor and node dialogs keep their original copyright headers.

Metadata

Release files for pyflowred 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pyflowred 0.1.0
File Size Uploaded
pyflowred-0.1.0.tar.gz 13.3 MB Details

Built distribution (wheel)

Table of built distributions (wheels) for pyflowred 0.1.0
File Interpreter ABI Platform
pyflowred-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 23.5 MB

Release files / pyflowred-0.1.0.tar.gz

Download URL pyflowred-0.1.0.tar.gz
Size 13.3 MB
Tags Source
SHA-256 checksum
How to use checksums
d2e7ef1b79f38bf403e639e0f53f0d7995ec256c0d3438f8d9e969e3f58267fe
BLAKE2b-256 checksum
How to use checksums
b6fc8d11cad48f779342940e3dd6a4c79b8015a2c5b7a75644520bdc9dc25cf1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.12.10 {"installer":{"name":"uv","version":"0.12.10","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / pyflowred-0.1.0-py3-none-any.whl

Download URL pyflowred-0.1.0-py3-none-any.whl
Size 10.2 MB
Tags Python 3
SHA-256 checksum
How to use checksums
21a0fa3045aa0734423b06b08f9aa8c30f5749994702790425e05919ea984d42
BLAKE2b-256 checksum
How to use checksums
195bf95295fce55d2d2d3ddb08bda0dbe62a58ab5aafd1d0d5f6c79da7c48659
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.12.10 {"installer":{"name":"uv","version":"0.12.10","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release history Release notifications | RSS feed

0.9.0

2 release files

0.8.2

2 release files

0.8.1

2 release files

0.8.0

2 release files

0.7.4

2 release files

0.7.3

2 release files

0.7.2

2 release files

0.7.1

2 release files

0.7.0

2 release files

0.6.0

2 release files

0.5.0

2 release files

0.4.0

2 release files

0.3.0

2 release files

0.2.0

2 release files

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page