comfyui-node-basics について
ComfyUI のノード開発者向けに、V3 API のノードクラス、スキーマ、実行メソッド、登録方法を解説する入門ガイドです。V1 の構造と両 API の主な違いも説明します。
主な機能
- 01V3 ノードクラスの構造
- 02スキーマによる入出力設定
- 03ComfyExtension による登録
- 04V1 と V3 の構造比較
活用シーン
- 01初めての V3 カスタムノードの作成
- 02ノードの入出力とカテゴリの定義
- 03ComfyUI へのノード登録
- 04レガシー V1 ノード構造の理解
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ jtydhr88/ comfyui-custom-node-skills --skill comfyui-node-basicsインストール後、Claude Code で/comfyui-node-basicsを入力して読み込まれたか確認します。
詳細
ComfyUI カスタムノードの基本(V3 API)
ComfyUI では、Python クラスを使ってノードを定義します。現在推奨されている方法は V3 API です。ノードは io.ComfyNode を継承し、スキーマと実行メソッドを定義します。
クイックスタート
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 ノードクラスの構造
V3 ノードには、次の定義が必要です。
io.ComfyNodeを継承するdefine_schema(cls)-io.Schemaを返すクラスメソッドexecute(cls, ...)- 計算を実行するクラスメソッド
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)
io.Schema のフィールド
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, # no cache sharing between identical instances (see lifecycle)
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
has_intermediate_output=False, # True for nodes with interactive UI that produce intermediate outputs
loop_boundary=None, # "start"/"end": core loop validation (v0.36+, experimental)
)
V3 ノードの登録
V3 ノードは、ComfyExtension と comfy_entrypoint() を使って登録します。
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 ノードの構造(旧方式の参考)
V1 ノードでは、クラス属性と NODE_CLASS_MAPPINGS を使います。
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"}
V3 と V1 の主な違い
| 項目 | V3 | V1 |
|---|---|---|
| 基底クラス | 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 |
重要なルール
node_idはすべてのノードでグローバルに一意である必要がありますexecute()のパラメーターは入力 ID と完全に一致する必要があります- V3 ではすべてのメソッドを
@classmethodにします(インスタンス状態はありません) - 出力数に一致する
io.NodeOutput(val1, val2, ...)を返します - カテゴリの階層には
/区切りを使います。例:"image/transform" - メニューから非表示にするには、カテゴリの先頭に
_を付けます。例:"_for_testing"
関連項目
comfyui-node-datatypes- データ型(IMAGE、LATENT、MASK など)comfyui-node-inputs- 入力設定の詳細comfyui-node-outputs- 出力の型と UI 出力comfyui-node-packaging- プロジェクトの構成とパッケージ化comfyui-node-lifecycle- 実行ライフサイクルとキャッシュ
コメント
Markdown 対応