Custom Stage
Custom Stage
- texts
- images
- videos
- audio
- models
- image
- images
- video
- audio
- text
- model
Every other node in ComfyTV is purpose-built: a Generate stage, a crop stage, a chroma keyer. Custom Stage is the opposite - it's the escape hatch. You hand it any regular ComfyUI workflow - one you saved yourself, or a .json someone posted - and it becomes a card that sits on the ComfyTV canvas and behaves like every other stage. In a pack of ~190 stages, it's how ComfyTV says "bring your own."
What you're actually looking at
First, thirty seconds of context, because Custom Stage only makes sense inside ComfyTV. ComfyTV (jtydhr88 - the same person behind the ComfyUI-InstantMesh port) is a canvas app that runs inside ComfyUI, TapNow/LibTV style. Stages - each with its own Run button, no global queue - connect into pipelines, and every output is kept as a project snapshot. This node lives in ComfyTV/Generate and is how your existing, battle-tested workflow gets to participate in all of that without being rebuilt from scratch.
The catch up front: Custom Stage renders in ComfyTV's experimental V2 skin only. If the card looks broken or won't open its Expose panel, flip the V2 toggle in ComfyTV settings first.
How it works
Pick a workflow in the workflow dropdown (it reads from ComfyTV's custom/ library - more below), then open Expose I/O on the card and tick which native nodes become sockets. The mapping is intuitive:
LoadImage/LoadVideo/LoadAudio/Load3Dfile pickers become image / video / audio / model input sockets.STRINGwidgets become text sockets with an editable box right on the card.INT/FLOAT/BOOLEAN/ combo widgets become plain parameters on the card.SaveImage/SaveVideo/SaveAudio/SaveGLBand text-preview nodes become the stage's outputs.
When you hit Run, the stage loads that workflow, rewires the ticked nodes so their inputs come from your card and wired sockets, then executes only the nodes needed to reach the exposed outputs as its own sub-run on ComfyUI's executor. Results land back on the sockets, and the first exposed output becomes the card's preview snapshot so it survives a reload. One neat detail: the exposure definition belongs to the workflow, so every Custom Stage pointing at the same workflow shares it - but parameter values stay per card.
The inputs and outputs that matter
Ignore most of the input list. project_id, parent_output_id, force_run_token, and custom_params are internal bookkeeping the ComfyTV frontend fills in - the tooltips say so, and you never set them by hand.
The two you actually touch:
- workflow - the combo dropdown. The library folder is
user/comfytv/workflows/custom/; you can drop JSONs in there, or click 🔗 Link workflow to pull straight from ComfyUI's own workflow library (live-linked, so edits in ComfyUI pick up on the next Run). Must be a normal GUI-format save - not "Save (API Format)". - main_prompt - fed to every exposed text input you marked as a prompt during Expose I/O.
The texts / images / videos / audio / models groups are the sockets that feed ticked media loaders, and the card can expose up to six outputs - image, images, video, audio, text, model - one per type (flip an image output to Batch to get images). Heads-up: these are ComfyTV types, not plain IMAGE tensors, so they wire into other ComfyTV stages - not ordinary ComfyUI nodes.
Installing it
cd ComfyUI/custom_nodes
git clone https://github.com/jtydhr88/ComfyTV
Restart, and nodes appear under the ComfyTV category. ComfyUI Manager can install it as "ComfyTV" if you'd rather go that way. The good news for once: pyproject declares zero Python dependencies - everything heavy it needs, ComfyUI already has. On ComfyUI Desktop or macOS, don't trust the relative cd; install into the running instance's absolute custom_nodes path instead. If the clone succeeds but ComfyTV never registers, that's the classic symptom of landing in the wrong instance.
Troubleshooting
The errors are unusually honest:
- "exposes no output yet - open Expose I/O" - you picked a workflow but never ticked an output node. Do that; it needs at least one.
- "produced no image/video output" - the workflow ran but its exposed output came back empty for the expected kind. Check the Save node actually writes what you exposed.
- "inputs references missing workflow node" - you renamed or deleted a node inside the source workflow after binding. Re-open the sidebar and rebind to the new node ID.
Where people get burned most: expecting a Custom Stage's outputs to plug into a normal graph, and forgetting the whole thing needs the V2 skin on. Sort those two and it's genuinely the one node that makes "all my old workflows" play inside the ComfyTV project model - worth the fiddly setup.
Inputs (11)
| Name | Type | Default | Description |
|---|---|---|---|
| force_run_token | INT | 00–2147483647 | Internal — bumped on Run to invalidate ComfyUI's input cache. |
| project_id | STRING | Internal — populated by the projectStore on the frontend. | |
| parent_output_id | INT | 00–2147483647 | Internal — lineage parent set by spawn handlers on the frontend. |
| workflow | COMBO | Any ComfyUI workflow; choose which of its nodes' inputs and outputs this stage exposes with the Expose I/O panel on the card. | |
| main_prompt | STRING | Main prompt — fed to every exposed text input marked as prompt. | |
| texts | COMFY_AUTOGROW_V3 | — | |
| images | COMFY_AUTOGROW_V3 | — | |
| videos | COMFY_AUTOGROW_V3 | — | |
| audio | COMFY_AUTOGROW_V3 | — | |
| models | COMFY_AUTOGROW_V3 | — | |
| custom_params | STRING | {} | Internal — JSON of user-defined parameter attachments/values for this node. |
Outputs (6)
| Name | Type | Description |
|---|---|---|
| image | COMFYTV_IMAGE | — |
| images | COMFYTV_IMAGES | — |
| video | COMFYTV_VIDEO | — |
| audio | COMFYTV_AUDIO | — |
| text | COMFYTV_TEXT | — |
| model | COMFYTV_MODEL | — |