Apidog

All-in-one Collaborative API Development Platform

API Design

API Documentation

API Debugging

API Mocking

API Automated Testing

How to Run a Flux Workflow ComfyUI as an API

This tutorial will guide you through the process of running Flux on ComfyUI as an API, opening up possibilities for automation and integration with other systems.

Mikael Svenson

Mikael Svenson

Updated on March 28, 2025

Flux is a state-of-the-art text-to-image model developed by Black Forest Labs, featuring advanced image generation capabilities. ComfyUI, on the other hand, is a powerful and modular diffusion model interface with a node-based workflow system. When combined, they create a robust solution for high-quality image generation that can be accessed programmatically.

Combining the power of Flux models with ComfyUI's versatility can significantly enhance your AI Image generation workflow. This tutorial will guide you through the process of running Flux on ComfyUI as an API, opening up possibilities for automation and integration with other systems.

💡
Before we dive into setting up our Flux ComfyUI API, let's talk about testing tools. When working with APIs, having a reliable testing platform is essential, and Apidog stands out as the premier Postman alternative in this space. 

Apidog offers a comprehensive API development ecosystem with features like automated testing, mock servers, and detailed documentation generation all in one unified platform.

button

Unlike Postman, Apidog provides seamless API lifecycle management with built-in debugging tools specifically optimized for complex workflows like those in ComfyUI. Its intuitive interface makes testing your Flux ComfyUI endpoints significantly more efficient, with collaborative features that enable team members to share and refine API configurations together.

If you're serious about API development and testing, Apidog's all-in-one solution will streamline your workflow considerably.

button

Setting Up Your Flux ComfyUI Environment

Before diving into the API implementation, we need to set up the necessary environment. We'll use Modal, a cloud platform that makes it easy to run serverless applications with GPU access.

Prerequisites for Flux ComfyUI

  • A Modal account (create one at modal.com)
  • Python 3.11 or later
  • Git installed on your local machine
  • Basic understanding of Python and API concepts

Building the Flux ComfyUI Container Image

Our first step is to create a container image that includes all necessary components for running Flux on ComfyUI. Let's break down the process:

import json
import subprocess
import uuid
from pathlib import Path
from typing import Dict

import modal

# Create a base image with necessary dependencies
image = (
    modal.Image.debian_slim(python_version="3.11")
    .apt_install("git")  # Install git for cloning ComfyUI
    .pip_install("fastapi[standard]==0.115.4")  # Web dependencies
    .pip_install("comfy-cli==1.3.5")  # ComfyUI CLI tool
    .run_commands(
        "comfy --skip-prompt install --nvidia --version 0.3.10"  # Install ComfyUI
    )
)

This code creates a Modal image based on Debian Slim with Python 3.11, then installs Git, FastAPI, and comfy-cli. The comfy-cli tool is then used to install ComfyUI itself.

Enhancing Your Flux ComfyUI with Custom Nodes

To unlock additional functionality, we'll add custom nodes to our ComfyUI installation:

image = (
    image.run_commands(
        "comfy node install was-node-suite-comfyui@1.0.2"  # Install WAS Node Suite
    )
    # Add more custom nodes as needed
)

The WAS Node Suite provides additional functionality for image generation and manipulation, which can be particularly useful when working with Flux models.

Setting Up Flux ComfyUI Model Download

Efficient model management is crucial for a smooth experience. We'll create a function to download the Flux model and store it in a persistent volume:

def hf_download():
    from huggingface_hub import hf_hub_download

    flux_model = hf_hub_download(
        repo_id="Comfy-Org/flux1-schnell",
        filename="flux1-schnell-fp8.safetensors",
        cache_dir="/cache",
    )

    # Symlink the model to the ComfyUI directory
    subprocess.run(
        f"ln -s {flux_model} /root/comfy/ComfyUI/models/checkpoints/flux1-schnell-fp8.safetensors",
        shell=True,
        check=True,
    )

# Create a persistent volume for model storage
vol = modal.Volume.from_name("hf-hub-cache", create_if_missing=True)

# Add the model download function to our image
image = (
    image.pip_install("huggingface_hub[hf_transfer]==0.26.2")
    .env({"HF_HUB_ENABLE_HF_TRANSFER": "1"})
    .run_function(
        hf_download,
        volumes={"/cache": vol},
    )
)

# Add our workflow JSON to the container
image = image.add_local_file(
    Path(__file__).parent / "workflow_api.json", "/root/workflow_api.json"
)

This code defines a function to download the Flux Schnell model from Hugging Face and create a symlink to the ComfyUI models directory. We also create a Modal Volume to persist the downloaded models between runs.

Interactive Flux ComfyUI Development

Before deploying as an API, it's useful to interactively test your Flux ComfyUI workflow:

app = modal.App(name="example-comfyui", image=image)

@app.function(
    allow_concurrent_inputs=10,  # Needed for UI startup
    max_containers=1,  # Limit to one container for interactive use
    gpu="L40S",  # Powerful GPU for Flux model inference
    volumes={"/cache": vol},  # Mount our cached models
)
@modal.web_server(8000, startup_timeout=60)
def ui():
    subprocess.Popen(
        "comfy launch -- --listen 0.0.0.0 --port 8000",
        shell=True
    )

You can run this with modal serve your_file.py and access the UI in your browser to design and test your workflows before implementing the API.

Implementing the Flux ComfyUI API

Now for the main event - turning ComfyUI into an API endpoint for Flux model inference:

@app.cls(
    allow_concurrent_inputs=10,  # Allow multiple concurrent API calls
    scaledown_window=300,  # Keep containers alive for 5 minutes after use
    gpu="L40S",
    volumes={"/cache": vol},
)
class ComfyUI:
    @modal.enter()
    def launch_comfy_background(self):
        # Start ComfyUI server in the background
        cmd = "comfy launch --background"
        subprocess.run(cmd, shell=True, check=True)

    @modal.method()
    def infer(self, workflow_path: str = "/root/workflow_api.json"):
        # Check ComfyUI server health
        self.poll_server_health()

        # Run workflow with comfy-cli
        cmd = f"comfy run --workflow {workflow_path} --wait --timeout 1200 --verbose"
        subprocess.run(cmd, shell=True, check=True)

        # Find output image
        output_dir = "/root/comfy/ComfyUI/output"
        workflow = json.loads(Path(workflow_path).read_text())
        file_prefix = [
            node.get("inputs")
            for node in workflow.values()
            if node.get("class_type") == "SaveImage"
        ][0]["filename_prefix"]

        # Return image as bytes
        for f in Path(output_dir).iterdir():
            if f.name.startswith(file_prefix):
                return f.read_bytes()

    @modal.fastapi_endpoint(method="POST")
    def api(self, item: Dict):
        from fastapi import Response

        # Load workflow template
        workflow_data = json.loads(
            (Path(__file__).parent / "workflow_api.json").read_text()
        )

        # Insert the prompt
        workflow_data["6"]["inputs"]["text"] = item["prompt"]

        # Generate unique ID for this request
        client_id = uuid.uuid4().hex
        workflow_data["9"]["inputs"]["filename_prefix"] = client_id

        # Save modified workflow
        new_workflow_file = f"{client_id}.json"
        json.dump(workflow_data, Path(new_workflow_file).open("w"))

        # Run inference
        img_bytes = self.infer.local(new_workflow_file)

        return Response(img_bytes, media_type="image/jpeg")

    def poll_server_health(self) -> Dict:
        import socket
        import urllib

        try:
            # Check if server is healthy
            req = urllib.request.Request("<http://127.0.0.1:8188/system_stats>")
            urllib.request.urlopen(req, timeout=5)
            print("ComfyUI server is healthy")
        except (socket.timeout, urllib.error.URLError) as e:
            # Stop container if server is unhealthy
            print(f"Server health check failed: {str(e)}")
            modal.experimental.stop_fetching_inputs()
            raise Exception("ComfyUI server is not healthy, stopping container")

This class defines the core API functionality:

  1. launch_comfy_background starts the ComfyUI server when the container launches
  2. infer runs a workflow and returns the generated image
  3. api is the FastAPI endpoint that accepts a prompt, modifies the workflow, and returns the image
  4. poll_server_health ensures the ComfyUI server is responsive

Testing Your Flux ComfyUI API

To test your API, you can create a simple client script:

import requests
import base64
from PIL import Image
import io
import argparse

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument("--prompt", default="A surreal landscape with floating islands and ethereal light")
    parser.add_argument("--endpoint", default="<https://your-modal-endpoint.modal.run>")
    args = parser.parse_args()

    # Send request to the API
    response = requests.post(
        f"{args.endpoint}/api",
        json={"prompt": args.prompt}
    )

    # Handle the response
    if response.status_code == 200:
        # Save and display the image
        image = Image.open(io.BytesIO(response.content))
        image.save("flux_output.jpg")
        print(f"Image generated and saved as flux_output.jpg")

        # Optional: display the image if in a suitable environment
        try:
            image.show()
        except:
            pass
    else:
        print(f"Error: {response.status_code}, {response.text}")

if __name__ == "__main__":
    main()

Optimizing Flux ComfyUI Performance

To ensure your API remains responsive and cost-effective, consider implementing the following optimizations:

1. Memory Snapshotting for Faster Flux ComfyUI Cold Starts

Cold starts can be a bottleneck for serverless applications. Modal offers memory snapshotting that can significantly reduce startup times:

@app.cls(
    allow_concurrent_inputs=10,
    gpu="L40S",
    volumes={"/cache": vol},
    memory_snapshot=modal.MemorySnapshot(
        snapshot_path="/root/comfy-snapshot",
        boot_command="comfy launch --background",
    ),
)
class ComfyUI:
    # Rest of the class implementation

2. Request Batching for Flux ComfyUI

For high-throughput scenarios, implementing request batching can improve efficiency:

@modal.method()
def batch_inference(self, prompts: list[str]):
    results = []
    for prompt in prompts:
        # Create workflow for each prompt
        client_id = uuid.uuid4().hex
        workflow_data = json.loads(
            (Path(__file__).parent / "workflow_api.json").read_text()
        )
        workflow_data["6"]["inputs"]["text"] = prompt
        workflow_data["9"]["inputs"]["filename_prefix"] = client_id

        # Save and process workflow
        new_workflow_file = f"{client_id}.json"
        json.dump(workflow_data, Path(new_workflow_file).open("w"))
        img_bytes = self.infer.local(new_workflow_file)
        results.append(img_bytes)

    return results

Advanced Flux ComfyUI API Features

Customizing Workflow Parameters

Extend your API to allow additional parameters beyond just the prompt:

@modal.fastapi_endpoint(method="POST")
def advanced_api(self, item: Dict):
    from fastapi import Response

    workflow_data = json.loads(
        (Path(__file__).parent / "workflow_api.json").read_text()
    )

    # Insert the prompt
    workflow_data["6"]["inputs"]["text"] = item["prompt"]

    # Optional: Set additional parameters if provided
    if "negative_prompt" in item:
        workflow_data["7"]["inputs"]["text"] = item["negative_prompt"]

    if "cfg_scale" in item:
        workflow_data["3"]["inputs"]["cfg"] = item["cfg_scale"]

    if "steps" in item:
        workflow_data["3"]["inputs"]["steps"] = item["steps"]

    # Generate unique ID
    client_id = uuid.uuid4().hex
    workflow_data["9"]["inputs"]["filename_prefix"] = client_id

    # Save and process workflow
    new_workflow_file = f"{client_id}.json"
    json.dump(workflow_data, Path(new_workflow_file).open("w"))
    img_bytes = self.infer.local(new_workflow_file)

    return Response(img_bytes, media_type="image/jpeg")

Handling Different Flux ComfyUI Models

Allow switching between different Flux models:

@modal.fastapi_endpoint(method="POST")
def model_selection_api(self, item: Dict):
    from fastapi import Response

    workflow_data = json.loads(
        (Path(__file__).parent / "workflow_api.json").read_text()
    )

    # Insert the prompt
    workflow_data["6"]["inputs"]["text"] = item["prompt"]

    # Select model if specified
    if "model" in item:
        if item["model"] == "flux-schnell":
            workflow_data["2"]["inputs"]["ckpt_name"] = "flux1-schnell-fp8.safetensors"
        elif item["model"] == "flux-turbo":
            workflow_data["2"]["inputs"]["ckpt_name"] = "flux1-turbo-fp8.safetensors"

    # Generate unique ID
    client_id = uuid.uuid4().hex
    workflow_data["9"]["inputs"]["filename_prefix"] = client_id

    # Save and process workflow
    new_workflow_file = f"{client_id}.json"
    json.dump(workflow_data, Path(new_workflow_file).open("w"))
    img_bytes = self.infer.local(new_workflow_file)

    return Response(img_bytes, media_type="image/jpeg")

Monitoring Your Flux ComfyUI API

Implementing proper monitoring is essential for production deployments:

@app.cls(
    # Other parameters
    monitor_agent=modal.MonitorAgent(),
)
class ComfyUI:
    # Existing implementation

    def log_request(self, prompt, model, processing_time):
        # Custom logging implementation
        print(f"Generated image for prompt: '{prompt}' using {model} model in {processing_time:.2f}s")

Conclusion: Unleashing the Power of Flux ComfyUI as API

By following this tutorial, you've learned how to transform ComfyUI with Flux models into a scalable, production-ready API service. This approach offers several advantages:

  1. Scalability: Handle multiple requests concurrently with automatic container scaling
  2. Flexibility: Customize workflows based on user requirements
  3. Integration: Connect your image generation capabilities with other applications
  4. Cost-effectiveness: Pay only for the compute you use

The combination of Modal's serverless infrastructure, ComfyUI's powerful workflow system, and Flux's state-of-the-art image generation creates a robust solution for a wide range of creative and business applications.

Whether you're building a creative tool, an e-commerce visualization system, or a content generation platform, running Flux on ComfyUI as an API provides the foundation for innovative AI-powered visual experiences.

button

Top 18 Best Load Testing Tools in 2025Viewpoint

Top 18 Best Load Testing Tools in 2025

Discover the top 18 open-source load testing tools for 2025. From enterprise solutions to lightweight options for API testing, this guide covers the best free tools to ensure your application performs under pressure.

Emmanuel Mumba

March 31, 2025

Top 15 Free API Testing tools 2025Viewpoint

Top 15 Free API Testing tools 2025

Explore the top 15 free API testing tools of 2025. From automation to performance testing, find the best tools to streamline API development and ensure reliability.

Emmanuel Mumba

March 31, 2025

How to Handle Grok-3 API Rate LimitsViewpoint

How to Handle Grok-3 API Rate Limits

This tutorial provides a comprehensive breakdown of Grok-3's rate limits and how to effectively work within these constraints.

Ashley Goolam

March 31, 2025