comfyui-node-basics
ComfyUI custom node fundamentals - V3 node structure, Schema, inputs/outputs, registration. Use when creating new ComfyUI custom nodes, defining node classes,…
ComfyUI advanced node patterns - MatchType, Autogrow, DynamicCombo, node expansion, MultiType, wildcard inputs. Use when building complex nodes with dynamic inputs, type matching, or node expansion.
$ npx -y skills add jtydhr88/comfyui-custom-node-skills --skill comfyui-node-advanced --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/comfyui-node-advancedContext preview
The summary Claude sees to decide when to auto-load this skill.
ComfyUI advanced node patterns - MatchType, Autogrow, DynamicCombo, node expansion, MultiType, wildcard inputs. Use when building complex nodes with dynamic inputs, type matching, or node expansion.
name: comfyui-node-advanced description: ComfyUI advanced node patterns - MatchType, Autogrow, DynamicCombo, node expansion, MultiType, wildcard inputs. Use when building complex nodes with dynamic inputs, type matching, or node expansion.
V3 provides advanced input patterns for dynamic, type-safe, and flexible node designs.
`MatchType` ensures that inputs and outputs sharing a template have the same type at connection time. Like generics in typed languages.
class PassThrough(io.ComfyNode):
@classmethod
def define_schema(cls):
# Template(template_id, allowed_types=AnyType) - optional type constraint
template = io.MatchType.Template("T")
return io.Schema(
node_id="PassThrough",
display_name="Pass Through",
category="utils",
inputs=[
io.MatchType.Input("value", template=template),
],
outputs=[
io.MatchType.Output(template=template, display_name="output"),
],
)
@classmethod
def execute(cls, value):
return io.NodeOutput(value)When the user connects an IMAGE to the input, the output automatically becomes IMAGE type.
class Switch(io.ComfyNode):
@classmethod
def define_schema(cls):
template = io.MatchType.Template("switch")
return io.Schema(
node_id="Switch",
display_name="Switch",
category="logic",
inputs=[
io.Boolean.Input("switch"),
io.MatchType.Input("on_false", template=template, lazy=True),
io.MatchType.Input("on_true", template=template, lazy=True),
],
outputs=[
io.MatchType.Output(template=template, display_name="output"),
],
)
@classmethod
def check_lazy_status(cls, switch, on_false=None, on_true=None):
if switch and on_true is None:
return ["on_true"]
if not switch and on_false is None:
return ["on_false"]
@classmethod
def execute(cls, switch, on_true, on_false):
return io.NodeOutput(on_true if switch else on_false)A single input that accepts several different types:
io.MultiType.Input("data",
types=[io.Image, io.Mask, io.Latent],
optional=True,
)Inputs that automatically add more slots as the user connects to them. Two template modes:
class ConcatImages(io.ComfyNode):
@classmethod
def define_schema(cls):
return io.Schema(
node_id="ConcatImages",
display_name="Concat Images",
category="image",
inputs=[
io.Autogrow.Input("images",
template=io.Autogrow.TemplatePrefix(
input=io.Image.Input("img"), # template for each slot
prefix="image_", # slot names: image_0, image_1, ...
min=2, # minimum visible slots (default 1)
max=16, # maximum slots (default 10, hard limit 100)
),
),
],
outputs=[io.Image.Output("IMAGE")],
)
@classmethod
def execute(cls, images: io.Autogrow.Type):
# images is a dict: {"image_0": tensor, "image_1": tensor, ...}
tensors = [v for v in images.values() if v is not None]
return io.NodeOutput(torch.cat(tensors, dim=0))io.Autogrow.Input("inputs",
template=io.Autogrow.TemplateNames(
input=io.Float.Input("val"),
names=["red", "green", "blue", "alpha"], # specific slot names
min=3, # first 3 are required
),
)
# Creates slots: "red" (required), "green" (required), "blue" (required), "alpha" (optional)**Key behaviors**:
A combo dropdown where each option reveals different sub-inputs:
class ProcessNode(io.ComfyNode):
@classmethod
def define_schema(cls):
return io.Schema(
node_id="ProcessNode",
display_name="Process Node",
category="processing",
is_output_node=True,
inputs=[
io.DynamicCombo.Input("mode", options=[
io.DynamicCombo.Option("resize", [
io.Int.Input("width", default=512, min=1, max=8192),
io.Int.Input("height", default=512, min=1, max=8192),
]),
io.DynamicCombo.Option("blur", [
io.Float.Input("radius", default=5.0, min=0.1, max=100.0),
]),
io.DynamicCombo.Option("sharpen", [
io.Float.Input("amount", default=1.0, min=0.0, max=10.0),
]),
]),
io.Image.Input("image"),
],
outputs=[io.Image.Output("IMAGE")],
)
@classmethod
def execute(cls, mode: io.DynamicCombo.Type, image, **kwargs):
# mode is a dict with the combo value + sub-inputs
# key for selected option matches the DynamicCombo input ID
if mode["mode"] == "resize":
width = mode["width"]
height = mode["height"]
# ... resize logic
return io.NodeOutput(image)**Nested DynamicCombo**:
io.DynamicCombo.Input("outer", options=[
io.DynamicCombo.Option("option1", [
io.DynamicCombo.Input("inner", options=[A curated collection of agent skills (for Claude Code and OpenAI Codex) for developing ComfyUI custom nodes. These skills give the agent comprehensive knowledge of the ComfyUI node system, covering both the V3 (recommended) and V1 (legacy) APIs.
Repo: jtydhr88/comfyui-custom-node-skills
ComfyUI custom node fundamentals - V3 node structure, Schema, inputs/outputs, registration. Use when creating new ComfyUI custom nodes, defining node classes,…
ComfyUI data types - IMAGE, LATENT, MASK, CONDITIONING, MODEL, CLIP, VAE, AUDIO, VIDEO, 3D types, widget types, and custom types. Use when working with ComfyUI…
ComfyUI frontend JavaScript extensions - hooks, widgets, sidebar tabs, commands, settings, toasts, dialogs. Use when adding UI features to custom nodes,…
ComfyUI node input types - INT, FLOAT, STRING, BOOLEAN, COMBO widgets, hidden inputs, optional inputs, lazy inputs, force_input. Use when configuring node…
ComfyUI node execution lifecycle - caching, fingerprint_inputs/IS_CHANGED, validate_inputs/VALIDATE_INPUTS, check_lazy_status, execution order. Use when…
ComfyUI V1 to V3 node migration - converting legacy nodes to the V3 API. Use when migrating existing custom nodes from V1 to V3, understanding differences…