Static Workflows¶
A static workflow uses a single workflow.json file — a ComfyUI API-format graph with parameter placeholders.
File Structure¶
workflows/wan22-i2v-fp8/
├── manifest.yaml # Metadata, inputs, outputs
└── workflow.json # ComfyUI API format with {{placeholders}}
Workflow JSON Format¶
The workflow JSON must be in ComfyUI API format, not the UI/graph format. The difference:
| API Format (required) | UI Format (wrong) | |
|---|---|---|
| Structure | Flat dict: {"1": {...}, "2": {...}} |
Nested: {"nodes": [...], "links": [...]} |
| Node IDs | String keys: "1", "2", "94" |
Integer IDs in objects |
| Connections | ["node_id", output_index] |
Link arrays with IDs |
| Export from ComfyUI | "Save (API Format)" or developer tools | Default save |
How to get API format¶
- Build your workflow in the ComfyUI graph editor
- Enable Dev Mode (Settings → Dev Mode → Enable)
- Click "Save (API Format)" — this saves as
workflow_api.json - Rename to
workflow.jsonand place in the workflow directory
Example: simplified structure¶
{
"1": {
"inputs": {
"ckpt_name": "v1-5-pruned-emaonly.safetensors"
},
"class_type": "CheckpointLoaderSimple",
"_meta": {"title": "Load Checkpoint"}
},
"2": {
"inputs": {
"text": "a mountain lake at sunset",
"clip": ["1", 1]
},
"class_type": "CLIPTextEncode",
"_meta": {"title": "Positive Prompt"}
},
"3": {
"inputs": {
"seed": 12345,
"steps": 20,
"cfg": 7.0,
"sampler_name": "euler",
"scheduler": "normal",
"denoise": 1.0,
"model": ["1", 0],
"positive": ["2", 0],
"negative": ["4", 0],
"latent_image": ["5", 0]
},
"class_type": "KSampler",
"_meta": {"title": "Sampler"}
}
}
Node connections use the format ["node_id", output_index]:
- ["1", 0] = node "1", first output (model)
- ["1", 1] = node "1", second output (clip)
- ["1", 2] = node "1", third output (vae)
Parameter Substitution¶
To make a static workflow configurable, replace hardcoded values with {{variable}} placeholders:
{
"1": {
"inputs": {
"ckpt_name": "{{checkpoint}}"
},
"class_type": "CheckpointLoaderSimple"
},
"2": {
"inputs": {
"text": "{{positive_prompt}}",
"clip": ["1", 1]
},
"class_type": "CLIPTextEncode"
},
"3": {
"inputs": {
"seed": "{{seed}}",
"steps": "{{steps}}",
"cfg": "{{cfg}}",
"sampler_name": "{{sampler_name}}",
"scheduler": "{{scheduler}}",
"denoise": "{{denoise}}",
"model": ["1", 0],
"positive": ["2", 0],
"negative": ["4", 0],
"latent_image": ["5", 0]
},
"class_type": "KSampler"
}
}
Each {{variable}} corresponds to an input id in the manifest. The backend scans all node inputs, finds {{...}} patterns, and replaces them with the user's form values.
Type conversion¶
"{{seed}}"(string placeholder) →42(integer) — the backend converts based on the input type"{{cfg}}"(string placeholder) →7.0(float)"{{positive_prompt}}"→"a mountain lake at sunset"(string stays string)
What you can't do with placeholders¶
- You cannot use placeholders for node connections (
["1", 0]) — the graph structure is fixed - You cannot conditionally include/exclude nodes — the graph is always the same
- You cannot repeat sections — the number of nodes is fixed
For these capabilities, use Dynamic Workflows.
Output Node Patching¶
Before sending the workflow to ComfyUI, the backend patches ALL output nodes to redirect files into the job's output directory. This happens automatically — you don't need to configure it in the workflow JSON.
The patching rules:
| Node Type | Condition | Output Path |
|---|---|---|
VHS_VideoCombine |
save_output=true |
comfyui-studio/{jobid}/video |
VHS_VideoCombine |
save_output=false |
Forced to true, comfyui-studio/{jobid}/intermediate |
SaveImage |
— | comfyui-studio/{jobid}/image |
PreviewImage |
— | comfyui-studio/{jobid}/preview |
This ensures all output files land in the job folder, never in ComfyUI's temp directory.
Current Static Workflows¶
| ID | Name | Models Used |
|---|---|---|
wan22-i2v-fp8 |
WAN 2.2 I2V (FP8 Fast) | WAN 2.2 FP8 high/low, UMT5-XXL FP8, WAN VAE, LightX2V LoRAs, RIFE |
wan22-i2v-kijai |
WAN 2.2 I2V (Kijai) | WAN 2.2 Kijai FP8 high/low, UMT5-XXL BF16, WAN VAE BF16, LightX2V distill |
wan22-i2v-lightx2v |
WAN 2.2 I2V (LightX2V) | WAN 2.2 LightX2V FP16 high/low, UMT5-XXL FP32, WAN VAE FP32, Remacri, RIFE |
All three are WAN 2.2 Image-to-Video workflows using different model formats and node implementations. They share the same input types (image, prompt, duration, CFG, seed) but use different ComfyUI nodes internally.