comfyui-node-basics

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

ComfyUI Custom Node Basics (V3 API)

ComfyUI自定义节点基础(V3 API)

ComfyUI uses Python classes to define nodes. The V3 API is the current recommended approach. Nodes inherit from
io.ComfyNode
and define a schema + execute method.
ComfyUI使用Python类定义节点,V3 API是当前官方推荐的实现方式。节点继承自
io.ComfyNode
,需定义schema和execute方法。

Quick Start

快速开始

python
from comfy_api.latest import ComfyExtension, io

class MyNode(io.ComfyNode):
    @classmethod
    def define_schema(cls):
        return io.Schema(
            node_id="MyNode",
            display_name="My Custom Node",
            category="my_category",
            inputs=[
                io.Image.Input("image"),
                io.Float.Input("strength", default=1.0, min=0.0, max=1.0, step=0.01),
            ],
            outputs=[
                io.Image.Output("IMAGE"),
            ],
        )

    @classmethod
    def execute(cls, image, strength):
        result = image * strength
        return io.NodeOutput(result)
python
from comfy_api.latest import ComfyExtension, io

class MyNode(io.ComfyNode):
    @classmethod
    def define_schema(cls):
        return io.Schema(
            node_id="MyNode",
            display_name="My Custom Node",
            category="my_category",
            inputs=[
                io.Image.Input("image"),
                io.Float.Input("strength", default=1.0, min=0.0, max=1.0, step=0.01),
            ],
            outputs=[
                io.Image.Output("IMAGE"),
            ],
        )

    @classmethod
    def execute(cls, image, strength):
        result = image * strength
        return io.NodeOutput(result)

V3 Node Class Structure

V3节点类结构

Every V3 node requires:
  1. Inherit from
    io.ComfyNode
  2. define_schema(cls)
    - classmethod returning
    io.Schema
  3. execute(cls, ...)
    - classmethod performing the computation
python
from typing_extensions import override
from comfy_api.latest import ComfyExtension, io

class ImageBrighten(io.ComfyNode):
    @classmethod
    def define_schema(cls):
        return io.Schema(
            node_id="ImageBrighten",          # unique identifier
            display_name="Brighten Image",     # shown in UI
            category="image/adjust",           # menu path
            description="Adjusts image brightness",
            inputs=[
                io.Image.Input("image"),
                io.Float.Input("factor", default=1.2, min=0.0, max=3.0, step=0.1),
            ],
            outputs=[
                io.Image.Output("IMAGE"),
            ],
        )

    @classmethod
    def execute(cls, image, factor):
        result = torch.clamp(image * factor, 0.0, 1.0)
        return io.NodeOutput(result)
所有V3节点都需要包含以下部分:
  1. 继承自
    io.ComfyNode
  2. define_schema(cls)
    - 类方法,返回
    io.Schema
    对象
  3. execute(cls, ...)
    - 类方法,执行节点的计算逻辑
python
from typing_extensions import override
from comfy_api.latest import ComfyExtension, io

class ImageBrighten(io.ComfyNode):
    @classmethod
    def define_schema(cls):
        return io.Schema(
            node_id="ImageBrighten",          # 唯一标识符
            display_name="Brighten Image",     # UI上展示的名称
            category="image/adjust",           # 菜单路径
            description="Adjusts image brightness",
            inputs=[
                io.Image.Input("image"),
                io.Float.Input("factor", default=1.2, min=0.0, max=3.0, step=0.1),
            ],
            outputs=[
                io.Image.Output("IMAGE"),
            ],
        )

    @classmethod
    def execute(cls, image, factor):
        result = torch.clamp(image * factor, 0.0, 1.0)
        return io.NodeOutput(result)

io.Schema Fields

io.Schema字段说明

python
io.Schema(
    node_id="UniqueNodeID",            # required: unique string ID
    display_name="Display Name",        # optional: shown in UI menus
    category="category/subcategory",    # menu hierarchy (default "sd")
    description="Node description",     # optional: tooltip text
    inputs=[...],                       # list of Input objects
    outputs=[...],                      # list of Output objects
    hidden=[...],                       # list of Hidden enum values
    is_output_node=False,               # True for nodes with side effects (save, preview)
    is_experimental=False,              # marks as experimental
    is_deprecated=False,                # marks as deprecated
    is_dev_only=False,                  # hidden unless dev mode enabled
    is_api_node=False,                  # marks as API-only node
    is_input_list=False,                # receive full lists instead of individual items
    not_idempotent=False,               # prevents caching
    accept_all_inputs=False,            # accept arbitrary inputs via **kwargs
    enable_expand=False,                # allow node expansion (subgraphs)
    search_aliases=["alias1", "alias2"],# alternative search terms
    essentials_category="Basic",        # optional: Essentials tab category
    price_badge=None,                   # optional: PriceBadge for API nodes
)
python
io.Schema(
    node_id="UniqueNodeID",            # 必填:全局唯一的字符串ID
    display_name="Display Name",        # 可选:UI菜单中展示的名称
    category="category/subcategory",    # 菜单层级(默认"sd")
    description="Node description",     # 可选:悬停提示文本
    inputs=[...],                       # Input对象列表
    outputs=[...],                      # Output对象列表
    hidden=[...],                       # Hidden枚举值列表
    is_output_node=False,               # 有副作用的节点设为True(保存、预览类节点)
    is_experimental=False,              # 标记为实验性功能
    is_deprecated=False,                # 标记为已废弃
    is_dev_only=False,                  # 仅开发模式下可见
    is_api_node=False,                  # 标记为仅API可用的节点
    is_input_list=False,                # 接收完整列表而非单个条目
    not_idempotent=False,               # 禁用缓存
    accept_all_inputs=False,            # 通过**kwargs接收任意输入
    enable_expand=False,                # 允许节点展开(子图)
    search_aliases=["alias1", "alias2"],# 搜索别名
    essentials_category="Basic",        # 可选: Essentials标签页分类
    price_badge=None,                   # 可选:API节点的价格标识
)

V3 Node Registration

V3节点注册

V3 nodes are registered via
ComfyExtension
and
comfy_entrypoint()
:
python
from typing_extensions import override
from comfy_api.latest import ComfyExtension, io

class MyNode(io.ComfyNode):
    @classmethod
    def define_schema(cls):
        return io.Schema(
            node_id="MyNode",
            display_name="My Node",
            category="my_nodes",
            inputs=[io.String.Input("text", multiline=True)],
            outputs=[io.String.Output()],
        )

    @classmethod
    def execute(cls, text):
        return io.NodeOutput(text.upper())


class MyExtension(ComfyExtension):
    @override
    async def get_node_list(self) -> list[type[io.ComfyNode]]:
        return [MyNode]


async def comfy_entrypoint() -> MyExtension:
    return MyExtension()
The
comfy_entrypoint()
function must be defined at the module level (in the file directly imported by ComfyUI).
V3节点通过
ComfyExtension
comfy_entrypoint()
注册:
python
from typing_extensions import override
from comfy_api.latest import ComfyExtension, io

class MyNode(io.ComfyNode):
    @classmethod
    def define_schema(cls):
        return io.Schema(
            node_id="MyNode",
            display_name="My Node",
            category="my_nodes",
            inputs=[io.String.Input("text", multiline=True)],
            outputs=[io.String.Output()],
        )

    @classmethod
    def execute(cls, text):
        return io.NodeOutput(text.upper())


class MyExtension(ComfyExtension):
    @override
    async def get_node_list(self) -> list[type[io.ComfyNode]]:
        return [MyNode]


async def comfy_entrypoint() -> MyExtension:
    return MyExtension()
comfy_entrypoint()
函数必须定义在模块顶层(放在ComfyUI直接导入的文件中)。

V1 Node Structure (Legacy Reference)

V1节点结构(旧版参考)

V1 nodes use class attributes and
NODE_CLASS_MAPPINGS
:
python
class MyNodeV1:
    CATEGORY = "my_category"
    FUNCTION = "execute"
    RETURN_TYPES = ("IMAGE",)
    RETURN_NAMES = ("image",)

    @classmethod
    def INPUT_TYPES(s):
        return {
            "required": {
                "image": ("IMAGE",),
                "strength": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0}),
            }
        }

    def execute(self, image, strength):
        return (image * strength,)

NODE_CLASS_MAPPINGS = {"MyNodeV1": MyNodeV1}
NODE_DISPLAY_NAME_MAPPINGS = {"MyNodeV1": "My Node V1"}
V1节点使用类属性和
NODE_CLASS_MAPPINGS
注册:
python
class MyNodeV1:
    CATEGORY = "my_category"
    FUNCTION = "execute"
    RETURN_TYPES = ("IMAGE",)
    RETURN_NAMES = ("image",)

    @classmethod
    def INPUT_TYPES(s):
        return {
            "required": {
                "image": ("IMAGE",),
                "strength": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0}),
            }
        }

    def execute(self, image, strength):
        return (image * strength,)

NODE_CLASS_MAPPINGS = {"MyNodeV1": MyNodeV1}
NODE_DISPLAY_NAME_MAPPINGS = {"MyNodeV1": "My Node V1"}

Key Differences: V3 vs V1

核心差异:V3 vs V1

AspectV3V1
Base class
io.ComfyNode
Plain class
Execute method
execute
classmethod (fixed name)
Instance method (custom name via
FUNCTION
)
Inputs
io.Schema(inputs=[...])
INPUT_TYPES()
dict
Outputs
io.Schema(outputs=[...])
RETURN_TYPES
tuple
Return value
io.NodeOutput(...)
Plain tuple
Registration
ComfyExtension
+
comfy_entrypoint()
NODE_CLASS_MAPPINGS
dict
StateNo instance state (classmethods)Instance state allowed
Hidden inputs
cls.hidden.prompt
, etc.
kwargs from
"hidden"
dict
对比项V3V1
基类
io.ComfyNode
普通类
执行方法
execute
类方法(固定名称)
实例方法(通过
FUNCTION
自定义名称)
输入定义
io.Schema(inputs=[...])
INPUT_TYPES()
字典
输出定义
io.Schema(outputs=[...])
RETURN_TYPES
元组
返回值
io.NodeOutput(...)
普通元组
注册方式
ComfyExtension
+
comfy_entrypoint()
NODE_CLASS_MAPPINGS
字典
状态管理无实例状态(全类方法)允许使用实例状态
隐藏输入
cls.hidden.prompt
来自
"hidden"
字典的kwargs

Important Rules

重要规则

  • node_id
    must be globally unique across all nodes
  • execute()
    parameters must match input IDs exactly
  • All methods are
    @classmethod
    in V3 (no instance state)
  • Return
    io.NodeOutput(val1, val2, ...)
    matching output count
  • Category uses
    /
    separator for hierarchy:
    "image/transform"
  • Prefix category with
    _
    to hide from menus:
    "_for_testing"
  • node_id
    必须在所有节点中全局唯一
  • execute()
    的参数必须和输入ID完全匹配
  • V3中所有方法都是
    @classmethod
    (无实例状态)
  • 返回的
    io.NodeOutput(val1, val2, ...)
    参数数量需和输出数量匹配
  • 分类使用
    /
    分隔层级:
    "image/transform"
  • 分类前缀加
    _
    可在菜单中隐藏:
    "_for_testing"

See Also

参考资料

  • comfyui-node-datatypes
    - Data types (IMAGE, LATENT, MASK, etc.)
  • comfyui-node-inputs
    - Input configuration details
  • comfyui-node-outputs
    - Output types and UI outputs
  • comfyui-node-packaging
    - Project structure and packaging
  • comfyui-node-lifecycle
    - Execution lifecycle and caching
  • comfyui-node-datatypes
    - 数据类型(IMAGE、LATENT、MASK等)
  • comfyui-node-inputs
    - 输入配置详情
  • comfyui-node-outputs
    - 输出类型和UI输出
  • comfyui-node-packaging
    - 项目结构和打包
  • comfyui-node-lifecycle
    - 执行生命周期和缓存