comfyanonymous/ComfyUI
HTTP and WebSocket
The ComfyUI server runs on aiohttp. All endpoints live on a single aiohttp.web.Application constructed by server.PromptServer (server.py). The OpenAPI spec at the repo root (openapi.yaml) is the formal contract; this page summarizes the most-used routes.
Public HTTP
Prompt and queue
| Route | Method | Purpose |
|---|---|---|
/prompt |
POST | Submit a prompt. Body: {prompt, client_id, extra_data, ...}. Returns {prompt_id, number, node_errors} |
/prompt |
GET | Returns the current state — running, pending, total, etc. |
/queue |
GET | Inspect the queue (running + pending) |
/queue |
POST | Manage the queue — clear, delete by id, etc. Body: {clear: true} or {delete: [id]} |
/interrupt |
POST | Cancel the currently-executing prompt |
/free |
POST | Free memory: {unload_models, free_memory} |
/history |
GET | Recent execution history |
/history/{prompt_id} |
GET | A single execution by id |
/history |
POST | Clear or delete history entries |
/object_info |
GET | Schema dump of every registered node — INPUT_TYPES, RETURN_TYPES, etc. |
/object_info/{class_type} |
GET | Schema for a single node |
/system_stats |
GET | Memory, device, and version info |
/embeddings |
GET | List embedding files in models/embeddings/ |
/extensions |
GET | List loaded JS extensions |
/features |
GET | Feature-flag negotiation entrypoint |
File I/O
| Route | Method | Purpose |
|---|---|---|
/upload/image |
POST | Upload an image to input/. Multipart: image + optional subfolder, type, overwrite |
/upload/mask |
POST | Upload a mask |
/view |
GET | Read a file. Query: filename, subfolder, type |
/view_metadata/{folder_name} |
GET | Read metadata from a model file (e.g., safetensors header) |
Models
| Route | Method | Purpose |
|---|---|---|
/models |
GET | All folders ↔ files map |
/models/{folder_name} |
GET | Files in one folder type |
Custom nodes
| Route | Method | Purpose |
|---|---|---|
/custom_nodes |
GET | List installed custom-node packages |
/custom_nodes/install |
POST | (Manager) Install a custom node |
/custom_nodes/{name} |
GET / DELETE | (Manager) Get info / uninstall |
When the Manager is enabled (--enable-manager), the manager package adds many more routes — they live in comfyui-manager, not in this repo.
Users (when --multi-user)
| Route | Method | Purpose |
|---|---|---|
/users |
GET | List users |
/userdata/{file} |
GET / POST | Read/write per-user files |
/settings/{user} |
GET / POST | Per-user settings JSON |
Subgraphs / node replacements
| Route | Method | Purpose |
|---|---|---|
/subgraphs |
GET / POST | Manage subgraph definitions |
Assets (when --enable-assets)
The full surface is in app/assets/api/routes.py. Highlights:
| Route | Method | Purpose |
|---|---|---|
/assets |
GET | List assets with filters |
/assets/{id} |
GET / PATCH / DELETE | Read / update tags+metadata / soft-delete |
/assets/upload |
POST | Multipart upload |
Internal HTTP (frontend-only)
/internal/* routes are not part of the public API. See api_server package for the endpoints currently exposed there.
WebSocket
GET /ws?clientId=<uuid> upgrades to WebSocket. The server pushes JSON text frames (status, progress, executing, executed) and binary frames (preview images).
Text frames
{"type": "status", "data": {"status": {"exec_info": {"queue_remaining": 0}}, "sid": "<client_id>"}}
{"type": "executing", "data": {"prompt_id": "...", "node": "<node_id>"}}
{"type": "progress", "data": {"value": 12, "max": 30, "prompt_id": "...", "node": "<node_id>"}}
{"type": "executed", "data": {"prompt_id": "...", "node": "<node_id>", "output": {...}}}
{"type": "execution_start" | "execution_cached" | "execution_error" | "execution_interrupted" | "execution_success"}The exact envelope is constructed by PromptServer.send_sync and friends in server.py.
Binary frames
Binary frames are typed by their first 4 bytes (BinaryEventTypes in protocol.py):
| Type | Constant | Payload |
|---|---|---|
1 |
UNENCODED_PREVIEW_IMAGE |
[type:4][format:4][image_bytes...] — legacy preview |
2 |
PREVIEW_IMAGE_WITH_METADATA |
Newer preview with extra metadata |
The newer event is gated by the client announcing supports_preview_metadata via feature flags (comfy_api/feature_flags.py). See hijack_progress in main.py for where the runtime decides which to send.
Middleware stack
In order of registration in server.py:
cache_control— setsCache-Controlheaders (read-only, mostlyno-cache).compress_body— when--enable-compress-response-body, gzip JSON/text responses.cors_middleware— when--enable-cors-header ORIGINis set.origin_only_middleware— blocks cross-site fetches when listening on loopback.block_external_middleware— sets a CSP header.deprecation_warning— logs once per legacy/scripts/uior/extensions/core/path.
TLS
Pass --tls-keyfile key.pem --tls-certfile cert.pem to expose ComfyUI over HTTPS. The README has an example openssl req command for self-signed certs.
Worked example: queue a prompt and watch it
import json, uuid, asyncio
import aiohttp
CLIENT_ID = str(uuid.uuid4())
async def main():
async with aiohttp.ClientSession() as s:
# Queue a prompt
prompt = { # truncated — real prompts have many nodes
"1": {"class_type": "CheckpointLoaderSimple", "inputs": {"ckpt_name": "..."}},
"2": {"class_type": "CLIPTextEncode", "inputs": {"text": "a fox", "clip": ["1", 1]}},
# ...
}
r = await s.post("http://127.0.0.1:8188/prompt", json={
"prompt": prompt, "client_id": CLIENT_ID
})
prompt_id = (await r.json())["prompt_id"]
# Watch progress
async with s.ws_connect(f"http://127.0.0.1:8188/ws?clientId={CLIENT_ID}") as ws:
async for msg in ws:
if msg.type == aiohttp.WSMsgType.TEXT:
evt = json.loads(msg.data)
if evt.get("type") == "executed" and evt["data"]["prompt_id"] == prompt_id:
break
# Fetch outputs
h = await s.get(f"http://127.0.0.1:8188/history/{prompt_id}")
print(await h.json())
asyncio.run(main())The frontend bundles the same dance internally; if you write your own UI or pipeline, this is the shape.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.