comfyanonymous/ComfyUI
comfy_api/
The versioned public API for custom-node authors. Anything a custom node imports from comfy_api.* is meant to stay stable across releases (modulo experimental surfaces in latest).
Layout
comfy_api/
├── feature_flags.py # Frontend/backend feature flag negotiation
├── generate_api_stubs.py # Pydantic stub generator for comfy_api_nodes/apis/
├── version_list.py # supported_versions list
├── util.py
├── util/ # Helpers
├── torch_helpers/ # Tensor helpers usable from custom nodes
├── input/, input_impl/ # (deprecated, kept for compat)
├── internal/ # Private types — do not import from custom nodes
│ ├── async_to_sync.py # create_sync_class wrapper
│ ├── api_registry.py # Version registry
│ └── singleton.py # ProxiedSingleton
├── latest/ # The current (unstable) public surface
│ ├── _io.py, _io_public.py # IO types and Schema for V3 nodes
│ ├── _ui.py, _ui_public.py # UI helpers
│ ├── _caching.py # CacheProvider, CacheContext, CacheValue
│ ├── _input/, _input_impl/ # Image/Audio/Video/Mask/Latent input wrappers
│ ├── _util/ # Misc helpers (VideoCodec, VideoContainer, …)
│ └── generated/ # Generated sync stubs
├── v0_0_1/ # Frozen v0.0.1 surface
└── v0_0_2/ # Frozen v0.0.2 surfaceWhat's in latest
The most-used names a custom node imports:
| Name | What it is |
|---|---|
io.Schema |
The V3 node schema constructor |
io.ComfyNode |
Base class for V3 nodes |
io.NodeOutput |
Wrapper around node outputs |
io.Image / Audio / Video / Mask / Latent / Float / Int / String / Boolean |
IO type declarations for Schema inputs and outputs |
io.Hidden |
Hidden inputs (prompt, dynprompt, extra_pnginfo, unique_id, …) |
ui (alias UI) |
UI-side helpers (e.g. node display options) |
ComfyExtension |
Abstract base for an extension; implements get_node_list() |
Input namespace |
Image, Audio, Mask, Latent, Video input wrappers (typed) |
InputImpl |
Concrete impls: VideoFromFile, VideoFromComponents |
Types |
VideoCodec, VideoContainer, VideoComponents, MESH, VOXEL, File3D |
Caching |
External cache provider API (register_provider, unregister_provider, CacheProvider, …) |
Execution.set_progress |
Report progress from inside a node |
NodeReplacement.register |
Register a runtime node replacement |
The full surface is in comfy_api/latest/__init__.py.
V3 schema example
The smallest possible V3 node, from comfy_extras/nodes_canny.py:
from comfy_api.latest import ComfyExtension, io
from typing_extensions import override
class Canny(io.ComfyNode):
@classmethod
def define_schema(cls):
return io.Schema(
node_id="Canny",
display_name="Canny",
category="image/preprocessors",
inputs=[
io.Image.Input("image"),
io.Float.Input("low_threshold", default=0.4, min=0.01, max=0.99, step=0.01),
io.Float.Input("high_threshold", default=0.8, min=0.01, max=0.99, step=0.01),
],
outputs=[io.Image.Output()],
)
@classmethod
def execute(cls, image, low_threshold, high_threshold) -> io.NodeOutput:
...
return io.NodeOutput(img_out)
class CannyExtension(ComfyExtension):
@override
async def get_node_list(self) -> list[type[io.ComfyNode]]:
return [Canny]
async def comfy_entrypoint() -> CannyExtension:
return CannyExtension()Compare with the V1 style in comfy/comfy_types/node_typing.py's ComfyNodeABC: V3 collapses INPUT_TYPES, RETURN_TYPES, FUNCTION, CATEGORY, and friends into a single declarative Schema and uses an execute classmethod.
Versioning
comfy_api/version_list.py lists the supported versions. The version registry under comfy_api/internal/api_registry.py tracks them. Custom nodes pin via from comfy_api.latest import ..., from comfy_api.v0_0_2 import ..., etc.
The repo guarantees:
latestmay break between releases.v0_0_1,v0_0_2(and future stable tags) are frozen — once shipped, the surface doesn't change.
comfy_api/internal/ is private and may change at any time, even though it's importable.
Feature flags
comfy_api/feature_flags.py negotiates frontend/backend capability flags so the server knows whether the connected client supports new features (e.g., supports_preview_metadata, used in hijack_progress in main.py).
Async-to-sync
comfy_api/internal/async_to_sync.py defines create_sync_class — a wrapper that turns the async ComfyAPI_latest into a synchronous ComfyAPISync mirror. This is generated at runtime so custom nodes can call API methods from sync code without spawning event loops.
Stub generation
comfy_api/generate_api_stubs.py regenerates the Pydantic schemas in comfy_api_nodes/apis/. Run it after editing schemas under comfy_api_nodes/apis/schemas/. CI runs it via update-api-stubs.yml.
Integration points
- Imported by
nodes.py, everycomfy_extras/*.pywritten in V3, and mostcomfy_api_nodes/*.py. - Wraps the executor's progress and caching subsystems so custom nodes don't have to reach into
comfy_execution/directly. - Exposes IO types tied to
comfy/comfy_types/node_typing.py(IO.IMAGE,IO.LATENT, etc.).
Where to start a change
- Adding a new IO type: extend
comfy/comfy_types/node_typing.py:IOand the V3 schema helpers incomfy_api/latest/_io.py. Don't forget the public re-export incomfy_api/latest/_io_public.py. - New API method visible to custom nodes: add an
async defon aProxiedSingletonsubclass incomfy_api/latest/__init__.py. The sync wrapper is generated automatically. - Bumping the version surface: add a new
comfy_api/v0_0_3/snapshot and add it toversion_list.supported_versions.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.