streamlit-node-editor-v2
A Streamlit Custom Component v2 for building ComfyUI- and Unreal Blueprints-style node graphs. Users can add nodes, edit parameters, connect typed ports, move and select nodes, select and delete connections, pan and zoom the canvas, and serialize the graph back to Python.
Installation
uv pip install streamlit-node-editor-v2
The package includes the compiled frontend assets. The public Python entry point is st_node_editor:
import streamlit as st
from streamlit_node_editor_v2 import st_node_editor
st.title("Pipeline editor")
graph = st_node_editor(key="pipeline")
if graph:
st.json(graph)
Component API
st_node_editor(
name="Node Editor",
node_defs=None,
height=700,
background_color="#080810",
show_border=True,
initial_nodes=None,
initial_connections=None,
key=None,
on_node_selected_change=None,
on_connection_selected_change=None,
on_connection_added_change=None,
on_connection_deleted_change=None,
)
Arguments
| Argument | Description |
|---|---|
name |
Name passed to the component. Defaults to "Node Editor". |
node_defs |
Dictionary defining the available node types. When omitted or empty, the built-in definitions are used. |
height |
Component height in pixels. Defaults to 700. |
background_color |
CSS color for the canvas. Defaults to "#080810". |
show_border |
Whether to draw a border around the canvas. |
initial_nodes |
Nodes placed when the component first loads. |
initial_connections |
Connections restored when the component first loads. |
key |
Stable Streamlit key. Required when reading event payloads from st.session_state. |
on_*_change |
Optional no-argument callbacks for component events. |
The function returns a dict-like component result with nodes and connections. It is empty or unavailable before the first frontend update.
Node definition JSON
node_defs is a mapping from the displayed node type name to its definition. The following is a complete example:
{
"Load Data": {
"category": "Sources",
"headerColor": "#4ade80",
"inputs": [],
"outputs": [
{"name": "data", "type": "DATAFRAME"}
],
"params": [
{
"key": "path",
"label": "CSV path",
"type": "string",
"default": "data/input.csv"
}
]
},
"Filter Rows": {
"category": "Transforms",
"headerColor": "#38bdf8",
"inputs": [
{"name": "data", "type": "DATAFRAME"}
],
"outputs": [
{"name": "data", "type": "DATAFRAME"}
],
"params": [
{
"key": "query",
"label": "Query",
"type": "textarea",
"default": "value > 0"
}
]
},
"Choose Model": {
"category": "Configuration",
"headerColor": "#c084fc",
"inputs": [],
"outputs": [
{"name": "model", "type": "MODEL"}
],
"params": [
{
"key": "model",
"label": "Model",
"type": "select",
"options": ["small", "medium", "large"]
}
]
}
}
Node definition fields
category: Palette grouping label.headerColor: CSS color for the node header.inputs: List of input ports.outputs: List of output ports.params: List of inline editable parameters.xandy: Optional initial position for built-in or supplied definitions.
Each port has a name and type. Input ports may also set maxConnections; the default is 1. Port types connect when their type names match, or when either side is ANY.
Each parameter has a key, label, and one of these types:
string: Single-line text input.textarea: Multiline text input.int: Integer input with step controls.float: Decimal input with step controls.select: Select box;optionsis required. Ifdefaultis omitted, the first option is used and returned in the graph state.
Initial graph JSON
Nodes can be supplied using initial_nodes:
[
{
"id": "load-1",
"type": "Load Data",
"x": 80,
"y": 120,
"params": {
"path": "data/input.csv"
}
},
{
"id": "filter-1",
"type": "Filter Rows",
"x": 420,
"y": 120,
"params": {
"query": "value > 0"
}
}
]
Connections can be supplied using initial_connections:
[
{
"id": "wire-1",
"fromNode": "load-1",
"fromPort": 0,
"toNode": "filter-1",
"toPort": 0
}
]
Port indexes are zero-based. The referenced node IDs and port indexes must exist.
Returned graph state
The component result has this shape:
{
"nodes": [
{
"id": "load-1",
"type": "Load Data",
"x": 80,
"y": 120,
"params": {"path": "data/input.csv"},
},
],
"connections": [
{
"id": "wire-1",
"fromNode": "load-1",
"fromPort": 0,
"toNode": "filter-1",
"toPort": 0,
},
],
}
User interactions
ADD NODEopens the node palette. Nodes can also be added from the canvas context menu.- Drag a node to reposition it.
- Click a node to select it.
DELETE NODEremoves selected nodes and their connections. - Drag between compatible ports to create a connection.
- Click a connection to select it. The connection is highlighted, and
DELETE CONNECTIONbecomes available. AUTO-CONNECTcreates compatible connections while avoiding cycles and connection limits.AUTO-DISCONNECTremoves all connections but keeps the nodes.RESETrestores pan and zoom.- Mouse wheel zooms the canvas. Middle-button dragging pans it; right-click opens the canvas context menu.
DeleteorBackspaceremoves selected nodes.
Event callbacks
Callbacks are no-argument functions. The event payload is available during the callback in the component's Streamlit session state. The callback names and payload keys are:
| Callback | Payload |
|---|---|
on_node_selected_change |
Selected node under st.session_state[key].node_selected |
on_connection_selected_change |
Selected connection under st.session_state[key].connection_selected |
on_connection_added_change |
New connection under st.session_state[key].connection_added |
on_connection_deleted_change |
Deleted connection under st.session_state[key].connection_deleted |
Example:
import streamlit as st
from streamlit_node_editor_v2 import st_node_editor
COMPONENT_KEY = "pipeline"
def selected_node():
st.session_state["last_event"] = {
"name": "node_selected",
"value": st.session_state[COMPONENT_KEY].node_selected,
}
def connection_added():
st.session_state["last_event"] = {
"name": "connection_added",
"value": st.session_state[COMPONENT_KEY].connection_added,
}
graph = st_node_editor(
key=COMPONENT_KEY,
on_node_selected_change=selected_node,
on_connection_added_change=connection_added,
)
if "last_event" in st.session_state:
st.json(st.session_state["last_event"])
The same pattern applies to on_connection_selected_change and on_connection_deleted_change. Events are triggers for the current rerun; the persistent graph is read from the component result.
Development setup
Requirements:
- Python 3.10 or newer.
- Node.js 24 or newer.
uvfor Python environment and package management.
Install frontend dependencies:
cd streamlit_node_editor_v2/frontend
npm install
Build and typecheck the frontend:
npm run typecheck
npm run build
npm run build cleans the frontend build directory, typechecks TypeScript, and writes one hashed index-*.js bundle to frontend/build.
Install the repository in editable mode from the project root:
uv pip install -e . --force-reinstall
Run the example app:
streamlit run example.py
When frontend source changes, rebuild the frontend and restart or refresh the Streamlit app so it serves the new hashed bundle.
Packaging
Build the frontend first:
cd streamlit_node_editor_v2/frontend
npm run build
cd ../..
Build the Python distributions from the project root:
uv build
The resulting dist/ directory contains the wheel and source distribution. The wheel includes streamlit_node_editor_v2/frontend/build and the package manifest that registers the v2 component asset directory.
Install and test the wheel locally:
uv pip install dist/streamlit_node_editor_v2-*.whl --force-reinstall
streamlit run example.py
Do not remove the [[tool.streamlit.component.components]] entry from the root pyproject.toml; Streamlit uses it to resolve the packaged index-*.js asset.
Metadata
Release files for streamlit-node-editor-v2 0.0.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| streamlit_node_editor_v2-0.0.1.tar.gz | 61.8 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| streamlit_node_editor_v2-0.0.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 121.2 kB
Release files / streamlit_node_editor_v2-0.0.1.tar.gz
| Download URL | streamlit_node_editor_v2-0.0.1.tar.gz |
|---|---|
| Size | 61.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
319abc0a89c2d5e8ed05ea2357da00ed9e7fbb58a38573848eee3cf6fadedced
|
|
BLAKE2b-256 checksum How to use checksums |
6591736a889822e583fb8f3c463fd1c35adef27149050768d82580de6b0eb733
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.7
|
Release files / streamlit_node_editor_v2-0.0.1-py3-none-any.whl
| Download URL | streamlit_node_editor_v2-0.0.1-py3-none-any.whl |
|---|---|
| Size | 59.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
81f9bb4ac44069df306ae85ee0d9420a307c45b1e2829e02a4d373b9a9136391
|
|
BLAKE2b-256 checksum How to use checksums |
08940e0f2c599f52873e6777515e5cd4d89efa5f2a63d3172dff7f17e0856b30
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.7
|
Security for streamlit-node-editor-v2 0.0.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.