You have a ComfyUI workflow in API format and a NodeTool graph to put it in. What is missing is a server to run it on. This page covers getting that endpoint and what has to be installed on it.
The nodes themselves, their properties, the workflow loader and the output slots are in ComfyUI.
Choosing a path
| Path | Node | Who holds the models | Cost | Reachable by |
|---|---|---|---|---|
| ComfyUI on your own machine | lib.comfy.RunWorkflow |
You, on your disk | Electricity | Nothing outside your machine, when it stays on loopback |
| ComfyUI on a rented GPU you expose | lib.comfy.RunWorkflow |
You, on the pod’s volume | Per minute while the pod is up | Anyone with the URL |
| NodeTool ComfyUI worker on a rented GPU | lib.comfy.RunWorkflowOnWorker |
You, on the pod’s volume | Per minute while the pod is up | The bearer token holder |
| Comfy Cloud | lib.comfy.RunWorkflowOnCloud |
Comfy | Per job, from your Comfy account | Comfy’s API key holder |
Three questions usually settle it:
- Do you have a GPU that fits the workflow? If yes, run ComfyUI locally and point the direct node at it. Nothing leaves the machine and there is no start-up wait.
- Do the weights have to stay yours? A rented GPU keeps them on a volume you control. Comfy Cloud does not: you submit a graph and Comfy supplies the models.
- Is the endpoint allowed to be public? A pod’s proxy URL is reachable by anyone who has it, since the direct node sends no credential. The NodeTool ComfyUI worker keeps ComfyUI on loopback inside the container and puts a bearer token in front of it.
Cold starts differ. A local ComfyUI is already warm. A rented pod pays for boot
plus whatever model downloads its volume still needs. Comfy Cloud has no boot,
but a full queue answers 429 and the plan’s concurrent-job limit is 1, 3, or 5.
A ComfyUI on your own machine
lib.comfy.RunWorkflow has an endpoint property, defaulting to
127.0.0.1:8188. A bare host:port gets http:// prepended. A full http://
or https:// URL is taken as given.
The process at that address has to serve ComfyUI’s HTTP API and its WebSocket on
the same port. NodeTool submits to /prompt, follows the run on /ws, downloads
finished files from /view, reconciles anything it missed from
/history/<prompt_id>, uploads connected media through /upload/image, and
posts /interrupt when you cancel. A stock ComfyUI serves all of it on one
port. See ComfyUI’s documentation for how to start it.
Nothing is sent on this path except the prompt, so the endpoint has to accept an unauthenticated submit.
Where 127.0.0.1 is resolved from
The ComfyUI nodes are server-tagged (node, workers, edge, never browser),
so the submit is made by the NodeTool backend, not by your browser tab.
127.0.0.1:8188 means “port 8188 on the machine running the NodeTool server”. In
the desktop app the bundled backend runs on your machine, so a local ComfyUI is
reachable with the default. If your NodeTool server runs somewhere else, a
Docker container or a self-hosted box, then that host is what must reach ComfyUI,
and loopback there is its loopback.
ComfyUI on another machine on the LAN
A ComfyUI bound to loopback is unreachable from any other machine, including the
one running NodeTool. ComfyUI’s flag for binding a wider interface is --listen, and
--port moves it off 8188. Both belong to ComfyUI, not to NodeTool: see
ComfyUI’s documentation for the exact syntax and for
install steps.
Once it listens, set endpoint to that machine’s host:port. Anyone who can
reach the address can submit prompts to it, so keep it on a network you trust.
A rented GPU
Expose ComfyUI yourself
Run ComfyUI on a pod and reach the port from outside: a RunPod pod’s HTTP proxy
URL, a Cloudflare tunnel, an SSH tunnel. Put the resulting https:// URL in
endpoint and use the direct node. The scheme is derived from the endpoint, so a
https:// address upgrades the WebSocket to wss:// on its own.
This publishes ComfyUI to whoever holds the URL. There is no Authorization
header on the direct node’s requests, so the proxy URL is the only secret, and
anyone with it can queue prompts, read /history, and download outputs. Put a
tunnel with its own auth in front of it, or use the worker below.
The NodeTool ComfyUI worker
Deploy ghcr.io/nodetool-ai/nodetool-worker-comfy:latest, which runs a
co-located ComfyUI that stays loopback-only inside the container, and drive it
with lib.comfy.RunWorkflowOnWorker. The node talks to the worker’s bridge over
wss://, authenticated with the worker’s bearer token in the worker_token
property. ComfyUI’s own ports are never published.
Provisioning, the profile and instance model, and the idle-stop and TTL guards
that stop a forgotten pod billing are in
Worker Deployment. Pick the ComfyUI image from the
Worker image preset dropdown, or pass
--image ghcr.io/nodetool-ai/nodetool-worker-comfy:latest on the CLI.
The worker node has no workflow loader in the editor, so its workflow property
and dynamic handles are filled in by hand. That and the bridge path’s slot naming
are in Known limitations.
Comfy Cloud
No GPU and no ComfyUI install. lib.comfy.RunWorkflowOnCloud submits the same
API-format prompt to https://cloud.comfy.org.
- Get a key at platform.comfy.org.
- Store it as
COMFY_API_KEY, either on the Comfy Cloud card in Settings → Models & Providers or withnodetool secrets store COMFY_API_KEY, which prompts for the value and writes it to the encrypted secret store.
The node declares COMFY_API_KEY in requiredSettings, so the editor badges it
as unconfigured until the key is there, and a run without it fails with
COMFY_API_KEY is required to run a workflow on Comfy Cloud.
The same key is sent with the workflow as extra_data.api_key_comfy_org, which
is what authenticates any partner (API) node inside the graph. One key covers
both the job and the API nodes in it.
Comfy’s own limits apply to the run: 1, 3, or 5 concurrent jobs by plan, and 30 minutes per job, 60 on Pro. Provider details are in Providers › Comfy Cloud.
comfy-api-proxy for the Comfy API v2
lib.comfy.RunWorkflow’s api property selects the transport. native is
ComfyUI’s own protocol. v2 sends the workflow through the Comfy API v2 client
the Cloud node uses, pointed at endpoint.
ComfyUI core does not serve /api/v2 yet, so a local ComfyUI needs Comfy-Org’s
own adapter in front of it. It translates v2 onto the native protocol:
pip install comfy-api-proxy
comfy-api-proxy --comfyui http://127.0.0.1:8188 --port 8189
Then set endpoint to 127.0.0.1:8189 and api to v2. Leaving api on v2
while endpoint points at a plain ComfyUI gets a 404 on /api/v2/jobs.
No API key is sent on this path, so the proxy has to accept an unauthenticated submit. What changes about the run, including the different output slot naming, is in Using the v2 API.
What the server must already have
A workflow in API format names its checkpoints, LoRAs, VAEs, and node classes by
string. Those strings are resolved by the ComfyUI that runs the prompt, not by
NodeTool. NodeTool clones the prompt, writes the connected input values into
prompt[nodeId].inputs[field], and posts it. It downloads no weights and
installs no extensions.
So the server needs, before the first run:
- Every model file the workflow names, under the filename the prompt uses.
sd_xl_base_1.0.safetensorsin the prompt is the name ComfyUI looks for in its own model folders, subfolder included. - Every custom node class the workflow uses. A
class_typethat is not registered on that ComfyUI is rejected at submit, exactly as it would be in ComfyUI’s own UI.
Media inputs are the exception: a connected image, audio, or video ref is uploaded to the server before the prompt goes out, so input files do not have to pre-exist.
A missing model or an unknown class_type fails the submit rather than the run.
The direct node reports Submit failed (400) with ComfyUI’s own response body
included, which names the offending node. The full message list is in
Troubleshooting.
Checking what is there
On a worker, the Python bridge exposes comfyObjectInfo() for the node catalog
and comfyModelsList(folder?) for the model files on the volume. No shipped
node calls either one. They are reachable from code against a connected bridge,
which is what Known limitations records. The
message shapes are in Python Bridge Protocol.
For a ComfyUI you reach directly, NodeTool offers no enumeration at all. Open ComfyUI’s own UI on that endpoint and check the loader dropdowns.
For Comfy Cloud there is nothing to check from NodeTool: what is installed is Comfy’s business, and the Comfy API enumerates no models. That is why the provider contributes none to the model pickers, as Providers › Comfy Cloud notes.
A first run to prove the wiring
Use the smallest workflow you have, a text-to-image with one checkpoint and one
SaveImage, before anything ambitious.
- Export it from ComfyUI with Save (API Format).
- Add Run ComfyUI Workflow to a graph and load the JSON with the header button. See Loading a workflow.
- Set
endpointif it is not127.0.0.1:8188. - Run it.
A healthy run writes this sequence to the node’s log:
Running ComfyUI workflow (7 nodes) on 127.0.0.1:8188
Execution started
Executing CheckpointLoaderSimple (#4)
Executing KSampler (#3)
Output from #9
A sampler progress bar appears while KSampler runs, and the image arrives on
the 9:image slot, keyed by the save node’s ComfyUI id. A second run of the same
prompt logs Reused cache for N node(s) instead of re-executing the unchanged
nodes.
If the log stops at WebSocket connection failed, the endpoint is wrong or
ComfyUI is not listening. If it stops at Submit failed (400), the server is
reachable but missing something the workflow names.
Related
- ComfyUI - the three nodes, their properties, the loader, and the outputs
- ComfyUI Recipes - worked examples of ComfyUI nodes inside NodeTool graphs
- Worker Deployment - renting a GPU and provisioning the ComfyUI worker image
- Providers - Comfy Cloud alongside every other provider, and where keys go