ControlNet Map Cache (ErosDiffusion)
Stop paying for the same ControlNet map twice
- source_browser
- source_original
- source_depth
- source_canny
- source_openpose
- source_lineart
- source_scribble
- source_softedge
- source_normal
- source_seg
- source_shuffle
- source_mediapipe_face
- source_custom
- map
Every ControlNet workflow does the same dumb thing: you run a preprocessor - canny, depth, openpose - on your source image, and ComfyUI happily re-runs it on every single queue. Iterating on one photo, new prompt, new sampler, and you regenerate the same edge map dozens of times. That's wasted VRAM and wasted minutes. The ControlNet Map Cache node is the fix: it generates the map once, saves it to disk, and on every later run serves you the cached file without ever touching the preprocessor.
The name is accurate - this is a cache layer, not a map generator. The README is blunt about it: the node does NOT generate maps. You still need a preprocessor upstream (canny from Comfy core, comfyui_controlnet_aux, Depth Anything v2/v3, whatever you like). What this node adds is the memory. Given the standing advice to lock composition with a structure pass and then iterate, that memory is what makes the loop cheap.
How it works
The trick is lazy inputs. Every source_<type> input is declared lazy, which means ComfyUI doesn't run the upstream preprocessor until this node explicitly asks for it. Before it asks, the node checks the cache: it looks in input/maps/<map_type>/ for a file matching your filename (basename only, extensions stripped, tries .png/.jpg/.jpeg/.webp). Cache hit - it loads the file from disk, outputs it, done, the preprocessor upstream never executes. Cache miss - it requests the connected preprocessor, and if save_if_new is on, saves the result so the next run hits.
Wire your preprocessors into this node, and its map output into Apply ControlNet - the graph reads "one source image, one cached map."
The inputs that actually matter
- filename - the identity of everything. It's the basename used for cache lookup, so keep it stable and matching. The pack's "Load Image ErosDiffusion" node extracts it from a source image for you; that's the intended flow.
- map_type -
auto(default) or one of depth, canny, openpose, lineart, scribble, softedge, normal, seg, shuffle, mediapipe_face, custom.autotries connected inputs first, then scans the filesystem, then requests everything. It's clever and the README admits it's currently bugged - for reliable daily use, pick a concrete type. - force_generation - here's the trap: it defaults to True. Out of the box this node ignores the cache and regenerates + overwrites on every run, which is the exact opposite of what you installed it for. Flip it to False and it behaves. This is the single most common reason people think the cache is broken when it's actually working as configured.
- generate_all - batch mode. Runs every connected
source_*preprocessor plus the original image and saves them all in one queue. Great for the first pass over a new image, then turn it off. - tags - comma-separated labels persisted to a SQLite DB so the browser can filter by them later. You can wire an LLM up to your source image and have it produce the tag list, which is a fun little pipeline.
Also worth knowing: map_type = "browser" is a pure pass-through - it just forwards the image from a connected CacheMap Browser node without saving anything.
Installing it
Through ComfyUI Manager, search "ControlnetMaps" and install. Manual route:
cd <your ComfyUI>/custom_nodes
git clone https://github.com/erosDiffusion/ErosDiffusion-ControlnetMaps.git
Restart ComfyUI and the nodes appear under the ErosDiffusion category, or load the generateMaps / useMaps workflows from the templates sidebar. No heavy Python dependencies - the changelog explicitly says a fresh install works out of the box, SQLite DBs are created on the fly. The only optional install is comfyui_controlnet_aux if you want more preprocessors to feed it. The starter import zip from the README (two pre-generated maps plus tags) is the fastest way to see the whole system without generating anything.
Common issues
- It regenerates every run - check
force_generation. It defaults to True; set it False. - "Cache miss" every time - your
filenamebasenames don't match, orcache_pathpoints somewhere other than where maps landed. The node strips extensions when comparing, sophoto.pngandphoto.jpgare the same key. - Nothing comes out - a lazy
source_<type>input only runs if it's actually connected. No wire, no map, no error. The README calls this out under troubleshooting. - auto mode behaves oddly - it's a known-bugged area. Pick an explicit
map_type.
The whole pack is beta and 0-impression new, so treat it as a young tool - the author (ErosDiffusion, also behind a ComfyUI Euler scheduler pack) is responsive to PRs, but expect rough edges.
Inputs (20)
| Name | Type | Default | Description |
|---|---|---|---|
| cache_path | STRING | Root directory for the cache. Leave empty to use the Comfy input/maps folder. | |
| filename | STRING | The unique identifier (base filename) for the map. Use 'Load Image ErosDiffusion' to extract this from a source image. | |
| map_type | COMBO | auto | The type of map to handle. 'browser' is a pure pass-through. |
| save_if_new | BOOLEAN | true | If True, saves the generated map to the cache directory if it wasn't found. |
| force_generation | BOOLEAN | true | If True, ignores existing cache and forces regeneration + overwrite. |
| generate_all | BOOLEAN | false | If True, triggers ALL connected preprocessors and saves their maps (respecting force_generation). |
| tagsopt | STRING | — | |
| source_browseropt | IMAGE | Lazy input. Connect CacheMap Browser here. Passes through the image without saving/modifying. | |
| source_originalopt | IMAGE | Lazy input. Connect the Original Image here. It will be saved to 'original' folder for overlay in browser. | |
| source_depthopt | IMAGE | Lazy input. Connect your depth Preprocessor here. Only runs if cache misses. | |
| source_cannyopt | IMAGE | Lazy input. Connect your canny Preprocessor here. Only runs if cache misses. | |
| source_openposeopt | IMAGE | Lazy input. Connect your openpose Preprocessor here. Only runs if cache misses. | |
| source_lineartopt | IMAGE | Lazy input. Connect your lineart Preprocessor here. Only runs if cache misses. | |
| source_scribbleopt | IMAGE | Lazy input. Connect your scribble Preprocessor here. Only runs if cache misses. | |
| source_softedgeopt | IMAGE | Lazy input. Connect your softedge Preprocessor here. Only runs if cache misses. | |
| source_normalopt | IMAGE | Lazy input. Connect your normal Preprocessor here. Only runs if cache misses. | |
| source_segopt | IMAGE | Lazy input. Connect your seg Preprocessor here. Only runs if cache misses. | |
| source_shuffleopt | IMAGE | Lazy input. Connect your shuffle Preprocessor here. Only runs if cache misses. | |
| source_mediapipe_faceopt | IMAGE | Lazy input. Connect your mediapipe_face Preprocessor here. Only runs if cache misses. | |
| source_customopt | IMAGE | Lazy input. Connect your custom Preprocessor here. Only runs if cache misses. |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| map | IMAGE | — |