Build a Custom ComfyUI Node

~20 minIntermediateYou'll build: A working ComfyUI custom node

In this tutorial you’ll build a ComfyUI custom node from scratch — a simple text-processing node that converts input text to uppercase. Along the way you’ll learn the node API, registration system, and packaging conventions.

This tutorial assumes ComfyUI is already installed via Thumper-Run. If you haven’t set it up yet, follow the First Image tutorial first.

Step 1: What Are Custom Nodes?

ComfyUI’s power comes from its node-based architecture. Each node is a Python class that receives inputs, processes them, and passes outputs to the next node in the graph.

Custom nodes let you extend ComfyUI with your own logic — anything from text manipulation to image filters to API calls. They live in the custom_nodes/ directory and are loaded automatically on startup.

Why Build Custom Nodes?

  • Add pre-processing or post-processing steps to your workflow
  • Integrate external APIs or local tools
  • Create reusable building blocks for complex pipelines
  • Share functionality with the ComfyUI community

A real-world example is the ThumperPromptEnhance node, which uses a local Qwen3-4B model to rewrite short prompts into detailed image descriptions — replacing a 10+ minute Gemma 12B pipeline with a ~40-second alternative.

Step 2: Create the Node Directory

Each custom node lives in its own folder inside ComfyUI’s custom_nodes/ directory. Create a new folder for your node:

bash
# Navigate to your ComfyUI installation
cd ~/.local/share/tr-desktop/apps/comfyui/
# Create the custom node directory
mkdir -p custom_nodes/my_text_tools

The directory name becomes the node pack’s identifier. Use snake_case for consistency with the ComfyUI ecosystem.

Directory Structure

A minimal custom node needs just one file:

custom_nodes/
my_text_tools/
__init__.py # Node class + registration

Larger node packs may split logic across multiple files, but the entry point is always __init__.py.

Step 3: Write the Node Class

Open custom_nodes/my_text_tools/__init__.py in your editor and paste the following:

python
class TextToUppercase:
"""Converts input text to uppercase."""
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"text": ("STRING", {
"multiline": True,
"default": "hello world"
}),
}
}
RETURN_TYPES = ("STRING",)
RETURN_NAMES = ("upper_text",)
FUNCTION = "to_upper"
CATEGORY = "text"
def to_upper(self, text):
return (text.upper(),)
# --- Registration (required) ---
NODE_CLASS_MAPPINGS = {
"TextToUppercase": TextToUppercase,
}
NODE_DISPLAY_NAME_MAPPINGS = {
"TextToUppercase": "Text to Uppercase",
}

Anatomy of a Node Class

  • INPUT_TYPES — classmethod that declares what inputs the node accepts and their types
  • RETURN_TYPES — tuple of output type strings (e.g. "STRING", "IMAGE", "INT")
  • RETURN_NAMES — human-readable labels for each output
  • FUNCTION — name of the method ComfyUI calls when executing the node
  • CATEGORY — determines where the node appears in the Add Node menu

Registration Dictionaries

Every __init__.py must export two dictionaries:

  • NODE_CLASS_MAPPINGS — maps unique node IDs to their Python classes
  • NODE_DISPLAY_NAME_MAPPINGS — maps node IDs to display names shown in the UI
Node IDs in NODE_CLASS_MAPPINGS must be globally unique across all installed custom nodes. Use a descriptive prefix to avoid collisions.

Step 4: Register and Test

ComfyUI discovers custom nodes at startup. To load your new node:

  1. If ComfyUI is running, stop it from the Thumper-Run dashboard
  2. Relaunch ComfyUI — click Launch on the ComfyUI card
  3. Once running, right-click the canvas and open Add Node → text
  4. You should see Text to Uppercase in the list. Click it to place a new node on the canvas — it appears as a rectangular block with a text input field and an upper_text output socket.
  5. Type some text in the input field, wire the output to another node (e.g. a "Show Text" node or a CLIP text encoder), and click Queue Prompt to run it
ComfyUI caches execution results — change your input to see updated output when testing.

Debugging

If your node doesn’t appear:

  • Check the ComfyUI console output for import errors
  • Verify NODE_CLASS_MAPPINGS is defined at module level (not inside a function)
  • Ensure the directory has an __init__.py file (not just a .py script)
  • Confirm the file has no syntax errors: python -c "import my_text_tools"

Testing the Output

To verify your node works, connect it to a "Show Text" node (if installed) or check the execution API response. A quick test:

bash
# Queue the workflow and check the output in the API response
curl -s http://localhost:8188/history | python -m json.tool | head -20

Step 5: Package for Sharing

If you want to share your node pack with others, follow these conventions:

Recommended Structure

my_text_tools/
__init__.py # Registration + imports
nodes/
text_upper.py # TextToUppercase class
text_reverse.py # TextReverse class (example)
requirements.txt # Python dependencies (if any)
README.md # Usage instructions

For node packs with external dependencies, include a requirements.txt. ComfyUI Manager and Thumper-Run will install these automatically.

Publishing

  • Push your node pack to a public Git repository
  • Submit to the ComfyUI Manager registry for community discovery
  • Or include the node pack directly in a Thumper manifest’s custom_nodes section
Include example workflows as .json files in your repository so users can test your nodes immediately after installation.

Key Takeaways

  • Custom nodes live in custom_nodes/<your_folder>/__init__.py
  • NODE_CLASS_MAPPINGS is required — without it, ComfyUI won’t discover your node
  • Restart ComfyUI to load new or modified nodes
  • Change your input between runs to bypass ComfyUI’s execution cache
  • Use unique node IDs with a descriptive prefix to avoid collisions

Next Steps