Workflow Serialization in ComfyUI: How Metadata Gets Embedded in PNG Files
ComfyUI embeds complete workflow metadata directly into PNG files as standard text chunks (tEXt) using Pillow's PngInfo object, storing the serialized node graph as JSON under the "prompt" key and any custom extra_pnginfo as additional text entries, enabling images to function as self-contained, portable workflow artifacts.
The Comfy-Org/ComfyUI repository implements a sophisticated workflow serialization system that captures the entire node graph state and embeds it directly into output PNG files. This technical architecture ensures that every generated image carries its complete generation recipe, allowing users to reconstruct, modify, or rerun the exact workflow that produced the visual output by simply loading the image file.
The Three-Stage Metadata Embedding Process
ComfyUI's metadata embedding operates through a precise three-stage pipeline that transforms the active node graph into embedded PNG text chunks.
Stage 1: Serializing the Workflow Graph
The serialization process begins in comfy_execution/graph_utils.py, where every node in the active workflow converts itself into a JSON representation via the Node.serialize() method. This method captures the node's class type, its input links, and an optional override_display_id parameter.
The GraphBuilder.finalize() method then aggregates these individual node serializations into a complete graph structure. This finalized JSON representation becomes the workflow prompt—a complete description of the node graph that the server passes back to the client as the prompt field in execution results.
Stage 2: Creating PNG Metadata with PngInfo
When a SaveImage or SaveImageWebsocket node executes, the actual metadata embedding occurs in nodes.py within the save_images() method. The implementation uses Pillow's PngInfo class to construct the metadata container:
- Workflow Prompt: The method adds the serialized graph JSON under the
"prompt"key usingmetadata.add_text("prompt", json.dumps(prompt)). - Custom Metadata: If the workflow includes
extra_pnginfo(a hidden field containing custom data such as workflow-wide IDs or version tags), the method iterates over these entries and adds each as a separate text chunk:metadata.add_text(key, json.dumps(value)).
The PngInfo object is then passed to Image.save() along with the output path and compression settings: img.save(os.path.join(full_output_folder, file), pnginfo=metadata, compress_level=self.compress_level).
Stage 3: Reading Metadata from Saved Images
The retrieval process occurs in server.py within the image-view endpoint. When ComfyUI serves a previously saved PNG, it uses Pillow to open the image and access the text attribute, which exposes the embedded tEXt chunks as a dictionary.
The server reconstructs the workflow by extracting the "prompt" value and parsing it as JSON, restoring the original node graph structure. This enables the UI to offer options to rerun or edit the workflow directly from the image file.
Key Implementation Files and Functions
Understanding the specific source files involved helps developers extend or debug the metadata system:
comfy_execution/graph_utils.py: ContainsNode.serialize()andGraphBuilder.finalize()which convert the active node graph into JSON format suitable for embedding.nodes.py: HousesSaveImage.save_images()which constructs thePngInfoobject, adds the"prompt"andextra_pnginfotext chunks, and writes the final PNG file.comfy_api/latest/_ui.py: Implements_create_png_metadata()for API-based PNG exports and animated PNG handling, using the same metadata structure as the standard save nodes.server.py: Handles metadata extraction via the image serving endpoints, reading thetextattribute from Pillow Image objects to retrieve the embedded workflow JSON.
Practical Code Examples
Saving Images with Embedded Workflow Metadata
The internal implementation in nodes.py demonstrates how to manually construct PNG metadata with embedded workflow data:
from PIL import Image, PngImagePlugin
import json
import os
def save_with_metadata(img, prompt_dict, extra_pnginfo, output_path, filename):
# Create PngInfo container
metadata = PngImagePlugin.PngInfo()
# Add the serialized workflow prompt
metadata.add_text("prompt", json.dumps(prompt_dict))
# Add any custom extra_pnginfo fields
if extra_pnginfo:
for key, value in extra_pnginfo.items():
metadata.add_text(key, json.dumps(value))
# Save with embedded metadata
full_path = os.path.join(output_path, filename)
img.save(full_path, pnginfo=metadata, compress_level=4)
return full_path
Extracting Workflow Data from Existing PNGs
To retrieve the embedded workflow from a ComfyUI-generated PNG:
from PIL import Image
import json
def extract_workflow(png_path):
with Image.open(png_path) as img:
# Access the text chunks dictionary
text_chunks = img.text
# Extract the workflow prompt
workflow_json = text_chunks.get("prompt", "{}")
workflow = json.loads(workflow_json)
# Extract extra_pnginfo (everything except "prompt")
extra_info = {
key: json.loads(value)
for key, value in text_chunks.items()
if key != "prompt"
}
return workflow, extra_info
# Usage example
workflow, extra = extract_workflow("output.png")
print(f"Node count: {len(workflow)}")
API-Based PNG Export with Metadata
When using the ComfyUI API to generate images with embedded metadata:
import requests
import json
payload = {
"prompt": {
"3": {
"inputs": {
"text": "masterpiece, best quality",
"clip": ["4", 0]
},
"class_type": "CLIPTextEncode"
},
# ... additional nodes
},
"extra_data": {
"extra_pnginfo": {
"workflow": {"id": "abc123", "version": "1.0"},
"custom_tag": "experimental"
}
},
"output_images": True
}
response = requests.post(
"http://localhost:8188/api/v1/save_image",
json=payload
)
# The returned PNG contains both "prompt" and "workflow" text chunks
Summary
- Workflow serialization in ComfyUI converts node graphs into JSON via
Node.serialize()incomfy_execution/graph_utils.py, creating a portable representation of the entire generation process. - Metadata embedding uses Pillow's
PngInfoclass innodes.pyto write the serialized workflow under the"prompt"key and customextra_pnginfodata as additional text chunks, storing everything as standard PNGtEXtchunks. - Metadata retrieval occurs in
server.pywhen the UI reads thetextattribute of Pillow Image objects, enabling the reconstruction of workflows from saved images for editing or rerunning. - The system supports both standard save nodes and API-based exports via
comfy_api/latest/_ui.py, ensuring consistent metadata handling across all output methods.
Frequently Asked Questions
What metadata format does ComfyUI use in PNG files?
ComfyUI stores metadata as standard PNG text chunks (tEXt) using the ISO 8859-1 character set. The workflow data is serialized as JSON strings and stored under specific keys: the "prompt" key contains the complete node graph serialization, while additional keys from extra_pnginfo store custom workflow metadata. This approach ensures compatibility with standard image viewers and editing tools while maintaining human-readable workflow data.
Can I disable metadata embedding in ComfyUI outputs?
Yes, metadata embedding can be disabled by setting the disable_metadata argument to True when calling save functions. In the SaveImage.save_images() method in nodes.py, the code explicitly checks if not args.disable_metadata: before executing metadata.add_text() calls. When disabled, the PngInfo object remains empty, resulting in PNG files without embedded workflow data, which is useful for privacy-conscious deployments or when reducing file size is critical.
How do I extract the workflow from a ComfyUI-generated PNG?
To extract the embedded workflow, open the PNG file using Pillow (Image.open()), access the .text attribute to retrieve the dictionary of text chunks, and parse the "prompt" value as JSON. The text attribute exposes all embedded tEXt chunks as a Python dictionary where keys are the metadata field names and values are the JSON strings. Any additional metadata stored in extra_pnginfo will appear as separate entries in this dictionary alongside the standard "prompt" key.
What is the difference between "prompt" and "extra_pnginfo" metadata?
The "prompt" metadata contains the complete serialized node graph—the entire workflow structure including all nodes, connections, and parameters required to reproduce the generation exactly. In contrast, extra_pnginfo stores ancillary custom data injected by specific nodes or the API, such as workflow IDs, version tags, author information, or experimental parameters. While "prompt" is mandatory for workflow reconstruction, extra_pnginfo provides extensibility for applications requiring additional tracking or categorization metadata without modifying the core workflow structure.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →