Open-Source Wikis

/

ComfyUI

/

Systems

/

Custom-nodes system

comfyanonymous/ComfyUI

Custom-nodes system

How third-party nodes plug into ComfyUI. The custom-nodes mechanism is the reason there is a thriving extension ecosystem — and the reason the runtime has so much defensive code (hook savers, deprecation middleware, isolation helpers).

Purpose

Let anyone add nodes to ComfyUI by dropping a Python module under custom_nodes/. The system supports:

  • Both V1 (NODE_CLASS_MAPPINGS) and V3 (comfy_entrypoint() → ComfyExtension) styles.
  • Per-node prestartup scripts for native dependency setup.
  • Whitelisting (--whitelist-custom-nodes) and full disable (--disable-all-custom-nodes).
  • Optional management via Comfy-Org/ComfyUI-Manager.

Discovery

folder_paths.get_folder_paths("custom_nodes") returns the configured custom-node directories (default <repo>/custom_nodes, plus anything from extra_model_paths.yaml).

Loading happens in two passes inside main.py:

  1. Prestartupexecute_prestartup_script walks each subdirectory and runs prestartup_script.py if it exists. This is where C extensions get built and ML weights get downloaded — before anything else has imported torch.
  2. Initnodes.init_extra_nodes(init_custom_nodes=True, init_api_nodes=...) (called from start_comfyui) imports each custom-node module and merges its registrations.

The Manager (when --enable-manager is on) hooks both passes — see comfyui_manager.prestartup() and comfyui_manager.start().

Anatomy of a custom node

A custom node is a Python module exposing one of:

V1 style

class MyNode:
    @classmethod
    def INPUT_TYPES(s):
        return {"required": {"value": ("FLOAT", {"default": 1.0})}}
    RETURN_TYPES = ("FLOAT",)
    FUNCTION = "do_thing"
    CATEGORY = "MyCategory"
    def do_thing(self, value):
        return (value * 2,)

NODE_CLASS_MAPPINGS = {"MyNode": MyNode}
NODE_DISPLAY_NAME_MAPPINGS = {"MyNode": "My Node"}

V3 style

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="MyCategory",
            inputs=[io.Float.Input("value", default=1.0)],
            outputs=[io.Float.Output()],
        )
    @classmethod
    def execute(cls, value):
        return io.NodeOutput(value * 2)

class MyExtension(ComfyExtension):
    async def get_node_list(self):
        return [MyNode]

async def comfy_entrypoint():
    return MyExtension()

The V3 style is the recommended one for new nodes. comfy_extras/ is the canonical reference — see comfy_extras/nodes_canny.py for a minimal example.

Registry

nodes.NODE_CLASS_MAPPINGS is the runtime registry: a dict[str, type] mapping class_type strings to node classes. nodes.NODE_DISPLAY_NAME_MAPPINGS is the dict[str, str] that controls the UI label.

init_extra_nodes does:

  1. For each comfy_extras/nodes_*.py and each custom_nodes/<dir>/: import the module.
  2. If the module exports NODE_CLASS_MAPPINGS, merge it into the global registry.
  3. If the module exports comfy_entrypoint, await it, then iterate await ext.get_node_list() and register each node via the V3 schema → V1 shim.
  4. Track timing per module and log a sorted list at startup for debugging.

server.PromptServer exposes the merged registry via GET /object_info.

Isolation and safety

The runtime takes several precautions because custom nodes execute arbitrary code:

  • Hook breakerhook_breaker_ac10a0.py saves references to a set of core functions before init and restores them between prompts, so a custom node can't permanently monkey-patch the runtime.
  • Deprecation middlewareserver.py's deprecation_warning middleware logs once per legacy frontend path. This catches old custom nodes hitting /scripts/ui or /extensions/core/.
  • Origin-only middleware — blocks cross-site fetches when listening on loopback, so a malicious page can't trick the browser into queuing prompts on 127.0.0.1:8188.
  • --disable-all-custom-nodes — useful when triaging a problem. Combine with --whitelist-custom-nodes <name> to selectively re-enable.

Frontend extensions

Custom-node packages can also ship a web/ subdirectory of JavaScript that the frontend loads. The frontend manager mounts it at /extensions/<name>/.... The legacy /scripts/ui and /extensions/core/ paths are deprecated; new extensions use the registered route.

ComfyUI-Manager interaction

When --enable-manager is set and comfyui-manager is installed (via manager_requirements.txt), the Manager:

  • Discovers available custom nodes from a curated index.
  • Manages installation, updates, and security checks.
  • Provides a UI for browsing and one-click install.

should_be_disabled(module_path) from comfyui_manager is consulted during prestartup so disabled nodes are skipped. With --disable-manager-ui, the background features (security checks, scheduled installs) keep running but the UI/endpoints are hidden.

API node sub-system

comfy_api_nodes/ is technically a custom-node-shaped collection of built-in modules (see comfy_api_nodes package page). It is loaded via the same init_extra_nodes call but gated by --disable-api-nodes separately.

Public surface custom nodes import

The supported public surface is comfy_api.latest and the frozen comfy_api/v0_0_* versions. See comfy_api package page for what's exported.

Custom nodes also commonly import:

  • comfy.utilsload_torch_file, helpers
  • comfy.model_managementget_torch_device, intermediate_device, intermediate_dtype
  • folder_paths — to register their own model directories

These are stable in practice but not officially versioned.

Integration points

Where to start a change

  • Adding a new built-in node: drop a file in comfy_extras/ — that's the same loader path as a custom node.
  • Changing what custom nodes can import: update comfy_api/latest/__init__.py. The __all__ list there is the canonical surface.
  • New isolation primitive: add to hook_breaker_ac10a0.py or as a middleware in server.py.

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Custom-nodes system – ComfyUI wiki | Factory