Previously the index was built only from the live registry, so a custom node that wasn't installed (a red "missing" node in a downloaded workflow) was invisible — the main point of the tool. Now: - Backend: utfcn_core split into build_context / build_index / match. build_index also emits curated candidates for uninstalled source types (curated-only), and a new POST /utfcn/match matches missing nodes by their serialized signature against installed core/other-pack nodes. - Frontend: nodeType() reads a missing placeholder's last_serialization.type; matchMissing() feeds serialized slots to /utfcn/match and merges the results; the right-click item moved to a canvas-level getNodeMenuOptions patch so it reaches missing placeholders too. Bulk dialog labels them "not installed". Replace a missing node with core without installing its pack. Links are rewired losslessly; widget values can't be carried for a node whose def is absent. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
UTFCN — Use The F***ing Core Nodes
A ComfyUI companion that nudges your workflows back toward core nodes. Over time a graph accumulates custom nodes that just re-implement things ComfyUI now ships itself. UTFCN spots those and helps you swap them out — fewer dependencies, more portable workflows.
It does three things:
- On add — drop a custom node that has a core (or otherwise installed) equivalent and, depending on the mode, UTFCN either shows a quiet tip or (in Force mode) auto-replaces it with the equivalent on the spot.
- Replace across a workflow —
Extensions ▸ UTFCN ▸ Replace custom nodes with core / available…(also in the command palette). It scans the open graph and shows a preview of every swap before anything changes. - Replace one node — right-click any custom node ▸ Replace with core / available.
Nothing is ever swapped without your say-so, and the engine only rewires slots it can move losslessly — anything it can't map is reported, not guessed.
Works on uninstalled ("missing") nodes
The headline case: open a downloaded workflow full of red missing nodes and
replace them with core equivalents without installing the packs at all.
ComfyUI keeps each missing node as a placeholder that remembers its original
type and wiring, so UTFCN can still match and swap it — via a curated rule (by
name) or by matching the node's serialized signature against your core nodes.
Both "Replace…" and the right-click item work on them; the bulk dialog labels
them ⚠ not installed. (Widget values aren't carried for a node whose
definition you don't have — links are.)
How it decides what's equivalent
The backend reads the live node registry (real INPUT_TYPES / RETURN_TYPES
and each node's source module) and ranks candidates in three tiers:
| Tier | Meaning | Auto-applied? |
|---|---|---|
| curated | a hand-written rule in mappings.json / user_mappings.json |
yes (verified) |
| exact | identical input names+types and output types to a core/other-pack node | yes (verified) |
| partial | can structurally stand in (accepts all inputs, provides all outputs) but names/slots differ | suggestion only |
"Available" means core is preferred, and if there's no core match it will offer an equivalent from a different installed pack as a fallback.
For an uninstalled node only curated (by name) and partial (by its serialized link signature) can apply — the exact tier needs the widget-level signature, which a node you haven't installed can't provide.
Shipped equivalences
mappings.json ships a small, hand-verified set (each checked lossless against
the real core signatures):
GetImageSize+(essentials) → coreGetImageSizeMaskPreview+(essentials) → coreMaskPreviewBOOLConstant/INTConstant/FloatConstant(KJNodes) → corePrimitiveBoolean/PrimitiveInt/PrimitiveFloatConvert Masks to Images/Mask Invert(WAS) → coreMaskToImage/InvertMask
Rules for nodes you don't have installed are simply ignored. Everything else is found live: exact-signature matches auto-apply, looser ones are suggested.
Adding your own equivalences
To bless a partial match as safe, or to fix up slots whose names differ, add a
rule to user_mappings.json (merged over the shipped mappings.json,
survives updates):
{
"rules": {
"SomeCustomNode": [
{
"to": "CoreNode",
"note": "why they're equivalent (shown in the preview)",
"inputs": { "old_input": "new_input" },
"widgets": { "old_widget": "new_widget" },
"outputs": { "old_output": "new_output" }
}
]
}
}
List targets in preference order (put the core node first). Any slot you don't
list is matched by identical name, then by type + order. After editing, run
Extensions ▸ UTFCN ▸ Refresh equivalence index (no restart needed).
Settings
UTFCN ▸ On add ▸ When adding a custom node that has a core / available equivalent:
- Off — do nothing.
- Suggest (default) — show a tip pointing at the equivalent.
- Force (auto-replace with core) — immediately swap it for the equivalent. Force only ever applies verified matches (curated or exact-signature); it never auto-applies a heuristic guess, and it never fires while you're opening or importing a workflow — only on nodes you add. Undo with Ctrl+Z.
Install
Clone into ComfyUI/custom_nodes/ and restart ComfyUI:
git clone https://github.com/ethanfel/ComfyUI-UTFCN
No Python dependencies. The node adds a single read-only server route
(/utfcn/scan) and a frontend extension.
License
GPL-3.0-or-later. See LICENSE.
