Files
2025-12-16 15:14:35 +08:00

11 KiB
Raw Permalink Blame History

ComfyUI Functional Usage Guide

This guide walks through the day-to-day workflow of using ComfyUI-Functional. For Chinese-language instructions, please refer to https://duanyll.com/2025/9/25/ComfyUI-Functional/.

Prerequisites

  • A working ComfyUI installation.
  • ComfyUI-Manager for one-click installs (optional, but recommended).
  • The Basic Data Handling node pack. Always use its LIST data type when passing arrays into or out of the functional nodes.

Installing or Updating the Extension

  1. Install through ComfyUI-Manager by searching for comfyui_functional.
  2. Manual installation: clone this repository under ComfyUI/custom_nodes and restart ComfyUI.
  3. Load the sample graphs found under example_workflows/ in this repo to experiment with the nodes.

⚠️ This node pack is intentionally hacky: it reaches into ComfyUI's scheduler to run and reuse node outputs. Expect breaking changes whenever ComfyUI is updated and keep test workflows handy.

Building Functions Inside ComfyUI

  1. Drop Function Parameter nodes for each argument your function accepts. Double-click the node title to rename it for clarity.
  2. Wire the parameters into the computation graph that forms the function body.
  3. Connect the last node of the body to a Function End node. Each function can return only one value; bundle multiple outputs into a LIST if needed.

Defining a simple function

Tips:

  • Nodes that do not depend on Function Parameter inputs are evaluated a single time during function definition and reused for every call. This makes it safe to load checkpoints or text encoders inside a function.
  • When you see Prompt has no outputs, it usually means you forgot to connect the result to Function End or to actually call the function (see below).

Calling Functions and Reusing Graphs

  1. Add a Call Function node.
  2. Connect the Function input to the Function End output.
  3. Provide arguments in the same order as the Function Parameter nodes.
  4. Use the Return output like a regular node output anywhere in your workflow.

Calling a function

You can feed the same function into multiple Call Function nodes to reuse logic throughout the graph, or even pass functions as arguments to build higher-order abstractions. Recursive calls are possible—feed the function object back into one of its own arguments—but always protect them with a termination condition to avoid infinite loops.

Working with Lists and Control Flow

To implement loops or other flow control primitives, rely on the high-order nodes found under duanyll/functional/high_order.

  • Always convert ComfyUI Data Lists into LIST objects before sending them into functional nodes. Data List values force eager evaluation and will crash or hang your workflow.
  • The table below summarizes the built-in high-order nodes; see docs/node-reference.md for parameter details and new nodes you can script yourself.
Node Purpose
Comap Apply multiple functions to the same input and collect the results.
Fold Reduce a list from left to right (functools.reduce-style).
Map Apply a function to every element in a LIST.
MapIndexed Like Map, but passes the element index as the second argument.
Nest Apply a function to an initial value n times.
NestWhile Keep applying the function until the predicate returns False; behaves like a while loop.
Select Filter a list based on a predicate function.
TakeWhile Consume items from the start of a list while the predicate stays True.

Mapping a function across a list

Implementation hint: the nodes rely on Python coroutines. Take a look at comfyui_functional/high_level.py and CoroutineNodeBase if you want to add your own high-order helpers.

Remote Function Calls

The Call Remote Function node lets you execute a function on another ComfyUI instance—either on a different GPU on the same machine or on a completely separate server. This is useful for:

  • Pipeline parallelism: Run different stages of your workflow on different hardware simultaneously.
  • Avoiding model swapping: Keep large models loaded on dedicated workers instead of loading/unloading them repeatedly on one GPU.
  • Distributed rendering: Spread batch processing across multiple machines.

Setting Up Remote Calls

  1. Start a ComfyUI server on the remote machine (or a second instance locally on a different port/GPU).
  2. Replace Call Function with Call Remote Function.
  3. Provide the base_url of the remote ComfyUI server (e.g., http://192.168.1.100:8188 or http://localhost:8189).
  4. Set timeout to an appropriate value for your workload.
  5. Enable use_shared_memory if both instances run on the same machine and you want to avoid tensor serialization overhead.

Capture vs. No-Capture Mode

Understanding the difference between local and remote function calls is critical:

Aspect Local Function (Call Function) Remote Function (Call Remote Function)
Capture mode Enabled by default; nodes not depending on parameters are evaluated once and reused Must be disabled (capture = False on Function End)
Model loading Load models outside the function; they get captured Load models inside the function body
Caching Node IDs change per call, so ComfyUI cache doesn't help Node IDs stay consistent, ComfyUI cache works normally
Serialization Not needed; values passed by reference Parameters and return values must be serializable

Why disable capture for remote calls?

  • Captured values (like loaded models) must be serialized and sent over the network.
  • Models, samplers, and other complex objects cannot be serialized.
  • By disabling capture, model loaders stay inside the function body and run on the remote server.
  • Since remote calls don't reassign node IDs, the remote ComfyUI instance can cache the loaded models between calls.

Example: Remote Image Generation

[Local Machine]                          [Remote GPU Server]

┌──────────────┐
│ Encode Prompt│
└──────┬───────┘
       │ (conditioning)
       ▼
┌──────────────────────┐    HTTP/WS     ┌─────────────────────────┐
│ Call Remote Function │ ─────────────→ │ Function Body:          │
│   base_url: ...      │                │   Load Checkpoint       │
│   param_0: cond      │                │   KSampler              │
│   param_1: seed      │                │   VAE Decode            │
└──────────┬───────────┘ ←───────────── │   (returns IMAGE)       │
           │ (image)                     └─────────────────────────┘
           ▼
┌──────────────┐
│  Save Image  │
└──────────────┘

Serialization Support

The following types can be passed as parameters or returned from remote functions:

  • Basic Python types: int, float, str, bool, list, dict, set, tuple
  • Binary data: bytes
  • NumPy arrays: numpy.ndarray
  • PyTorch tensors: torch.Tensor (CPU only; GPU tensors are moved to CPU automatically)
  • PIL images: PIL.Image

Types that cannot be serialized (and must stay inside the remote function body):

  • Models (checkpoints, VAE, CLIP, ControlNet, etc.)
  • Samplers and schedulers
  • Custom objects without explicit serialization support

Shared Memory Optimization

When both ComfyUI instances run on the same physical machine, enable use_shared_memory to pass PyTorch tensors via shared memory instead of JSON serialization. This dramatically reduces overhead for large tensors (images, latents).

Note: Shared memory only works for CPU tensors on the same machine. Cross-machine calls always use standard serialization.

Using Side Effects Safely

Some situations call for side effects (logging, collecting intermediate results, pacing execution). The following nodes make that practical:

  • Sow / Reap: Sow pushes values into an implicit list, Reap returns everything collected so far. Chain the signal input/output with the surrounding nodes to enforce execution order.
  • Inspect: Attach a raw node output to the value output on Inspect to probe intermediate values without forcing the entire branch to run at graph build time. Only runs when its signal output is consumed.
  • Sleep: Adds a delay to make Inspect output easier to read in fast loops.

Collecting values in a loop

Because these nodes may disable ComfyUI's cache for correctness, expect longer runtimes whenever side effects are involved.

Debugging Checklist

  • Function body outputs must terminate at Function End. Any loose connection that depends on Function Parameters will fire eagerly and break evaluation.
  • Protect recursive or long-running loops with max_depth or NestWhile predicates.
  • Use Inspect liberally to tap into conditionals. It prevents ComfyUI from rendering both branches of an If/Else when only one should run.

Example Workflows

The example_workflows/ directory ships with working graphs:

  • functional-map.json – demonstrates Map/MapIndexed on a numeric LIST.
  • functional-list-param.json – shows how to juggle multiple parameters plus list inputs.
  • functional-nested-calls.json – functions that call other functions (mirrors the blog demo).
  • functional-recursion.json – guarded recursion via Call Function.
  • functional-sow-reap.json & functional-inspect.json – Sow/Reap, Inspect, and Sleep in context.

Open them via ComfyUI's load workflow dialog, study the wiring, and start adapting them for your projects.

Common Pitfalls

  • "Prompt has no outputs": add a Call Function node or ensure something depends on the Call Function output.
  • Data List lock-ups: convert everything to LIST using Basic Data Handling's conversion nodes before interacting with functional nodes.
  • Stale cached results: the pack disables caching when it detects side effects. If you still see stale data, clear your ComfyUI cache manually.

Further Reading