| name | comfyui-node-outputs |
| description | ComfyUI node output types - NodeOutput, UI outputs, PreviewImage, PreviewMask, SavedImages, PreviewAudio, PreviewText, PreviewVideo. Use when returning results from nodes, displaying previews, or saving output files. |
ComfyUI Node Outputs
Nodes return data through io.NodeOutput. V3 provides built-in UI helpers for previews and file saving.
Basic Output
class SimpleNode(io.ComfyNode):
@classmethod
def define_schema(cls):
return io.Schema(
node_id="SimpleNode",
display_name="Simple Node",
category="example",
inputs=[io.Float.Input("a"), io.Float.Input("b")],
outputs=[
io.Float.Output("SUM"),
io.Float.Output("PRODUCT"),
],
)
@classmethod
def execute(cls, a, b):
return io.NodeOutput(a + b, a * b)
Output Configuration
io.Schema(
outputs=[
io.Image.Output("IMAGE"),
io.Int.Output("COUNT"),
io.Float.Output("VALUE", display_name="Result"),
io.String.Output("TEXT", tooltip="The processed text"),
io.Image.Output("FRAMES", is_output_list=True),
],
)
NodeOutput Variants
return io.NodeOutput(image_tensor, mask_tensor)
return io.NodeOutput(ui=ui.PreviewImage(images, cls=cls))
return io.NodeOutput(image_tensor, ui=ui.PreviewImage(images, cls=cls))
return io.NodeOutput()
return io.NodeOutput(block_execution="Reason for blocking")
return io.NodeOutput(output_ref, expand=graph.finalize())
UI Preview Helpers
Import ui from comfy_api.latest:
from comfy_api.latest import io, ui
PreviewImage
Display image previews on the node. Saves to temp directory automatically.
class PreviewNode(io.ComfyNode):
@classmethod
def define_schema(cls):
return io.Schema(
node_id="PreviewNode",
display_name="Preview Image",
category="image",
is_output_node=True,
inputs=[io.Image.Input("images")],
outputs=[],
hidden=[io.Hidden.prompt, io.Hidden.extra_pnginfo],
)
@classmethod
def execute(cls, images):
return io.NodeOutput(ui=ui.PreviewImage(images, cls=cls))
PreviewMask
return io.NodeOutput(ui=ui.PreviewMask(masks, cls=cls))
PreviewAudio
return io.NodeOutput(ui=ui.PreviewAudio(audio, cls=cls))
PreviewVideo
return io.NodeOutput(ui=ui.PreviewVideo(saved_video_results))
PreviewText
Display text output:
return io.NodeOutput(ui=ui.PreviewText(value))
PreviewUI3D
Display 3D model preview:
return io.NodeOutput(ui=ui.PreviewUI3D(
model_file=saved_result,
camera_info=camera_dict,
bg_image=image_tensor,
))
Saving Images
Using ImageSaveHelper
The ui.ImageSaveHelper class provides static methods for various image formats:
results = ui.ImageSaveHelper.save_images(
images,
filename_prefix="ComfyUI",
folder_type=io.FolderType.output,
cls=cls,
compress_level=4,
)
saved_ui = ui.ImageSaveHelper.get_save_images_ui(images, "ComfyUI", cls=cls)
return io.NodeOutput(ui=saved_ui)
result = ui.ImageSaveHelper.save_animated_png(
images, "anim", io.FolderType.output, cls=cls, fps=12.0, compress_level=4
)
saved_ui = ui.ImageSaveHelper.get_save_animated_png_ui(images, "anim", cls=cls, fps=12.0, compress_level=4)
result = ui.ImageSaveHelper.save_animated_webp(
images, "anim", io.FolderType.output, cls=cls,
fps=12.0, lossless=False, quality=80, method=4
)
saved_ui = ui.ImageSaveHelper.get_save_animated_webp_ui(
images, "anim", cls=cls, fps=12.0, lossless=False, quality=80, method=4
)
Simple save node example:
class SaveImageNode(io.ComfyNode):
@classmethod
def define_schema(cls):
return io.Schema(
node_id="SaveImageNode",
display_name="Save Image",
category="image",
is_output_node=True,
inputs=[
io.Image.Input("images"),
io.String.Input("filename_prefix", default="ComfyUI"),
],
outputs=[],
hidden=[io.Hidden.prompt, io.Hidden.extra_pnginfo],
)
@classmethod
def execute(cls, images, filename_prefix):
saved = ui.ImageSaveHelper.get_save_images_ui(images, filename_prefix, cls=cls)
return io.NodeOutput(ui=saved)
Manual Image Saving
import os
import json
import numpy as np
from PIL import Image as PILImage
from PIL.PngImagePlugin import PngInfo
import folder_paths
class CustomSaveNode(io.ComfyNode):
@classmethod
def define_schema(cls):
return io.Schema(
node_id="CustomSaveNode",
display_name="Custom Save",
category="image",
is_output_node=True,
inputs=[
io.Image.Input("images"),
io.String.Input("prefix", default="output"),
],
outputs=[],
hidden=[io.Hidden.prompt, io.Hidden.extra_pnginfo],
)
@classmethod
def execute(cls, images, prefix):
output_dir = folder_paths.get_output_directory()
results = []
for i, image in enumerate(images):
img_array = np.clip(255.0 * image.cpu().numpy(), 0, 255).astype(np.uint8)
pil_image = PILImage.fromarray(img_array)
metadata = PngInfo()
if cls.hidden.prompt:
metadata.add_text("prompt", json.dumps(cls.hidden.prompt))
if cls.hidden.extra_pnginfo:
for k, v in cls.hidden.extra_pnginfo.items():
metadata.add_text(k, json.dumps(v))
filename = f"{prefix}_{i:05d}.png"
filepath = os.path.join(output_dir, filename)
pil_image.save(filepath, pnginfo=metadata)
results.append(ui.SavedResult(
filename=filename,
subfolder="",
type=io.FolderType.output,
))
return io.NodeOutput(ui=ui.SavedImages(results))
Saving Audio
The ui.AudioSaveHelper supports FLAC, MP3, and Opus formats:
results = ui.AudioSaveHelper.save_audio(
audio,
filename_prefix="audio",
folder_type=io.FolderType.output,
cls=cls,
format="flac",
quality="128k",
)
saved_ui = ui.AudioSaveHelper.get_save_audio_ui(audio, "audio", cls=cls, format="flac", quality="128k")
return io.NodeOutput(ui=saved_ui)
class SaveAudioNode(io.ComfyNode):
@classmethod
def define_schema(cls):
return io.Schema(
node_id="SaveAudioNode",
display_name="Save Audio",
category="audio",
is_output_node=True,
inputs=[
io.Audio.Input("audio"),
io.String.Input("prefix", default="audio"),
io.Combo.Input("format", options=["flac", "mp3", "opus"], default="flac"),
],
outputs=[],
hidden=[io.Hidden.prompt, io.Hidden.extra_pnginfo],
)
@classmethod
def execute(cls, audio, prefix, format):
saved = ui.AudioSaveHelper.get_save_audio_ui(audio, prefix, cls=cls, format=format)
return io.NodeOutput(ui=saved)
Temporary Previews vs Permanent Saves
- Previews (PreviewImage, etc.) save to the
temp directory and are ephemeral
- Saves (ImageSaveHelper.save_images) save to the
output directory permanently
- Use
io.FolderType.temp, io.FolderType.output, or io.FolderType.input
V1 Output Patterns (Legacy Reference)
class V1SaveNode:
RETURN_TYPES = ()
OUTPUT_NODE = True
FUNCTION = "save"
def save(self, images, prefix):
return {
"ui": {
"images": [
{"filename": "out.png", "subfolder": "", "type": "output"}
]
}
}
class V1PreviewAndOutput:
RETURN_TYPES = ("IMAGE",)
OUTPUT_NODE = True
FUNCTION = "run"
def run(self, image):
return {
"ui": {"images": [...]},
"result": (processed_image,),
}
See Also
comfyui-node-basics - Node structure and Schema
comfyui-node-datatypes - Data type formats
comfyui-node-lifecycle - Execution flow