DictMerge (Yogurt Nodes)
Slam up to 32 dicts together — and decide who wins the collisions
- dict1
- dict2
- dict3
- dict4
- dict5
- dict6
- dict7
- dict8
- dict9
- dict10
- dict11
- dict12
- dict13
- dict14
- dict15
- dict16
- dict17
- dict18
- dict19
- dict20
- dict21
- dict22
- dict23
- dict24
- dict25
- dict26
- dict27
- dict28
- dict29
- dict30
- dict31
- dict32
- merged_dict
DictMerge takes two dictionaries as required inputs and merges them into one. Then it keeps going - up to 32 optional inputs deep, so you can chain a whole pile of config blobs, API responses, or metadata dicts into a single combined result. It's the "combine everything into one dict" node, and in data-heavy ComfyUI graphs it's the glue that turns scattered JSON sources into one coherent payload.
The question that actually matters here isn't "does it merge?" - it's "who wins when two dicts have the same key?" That's the overwrite toggle, defaulting to true. With overwrite on, later dicts overwrite earlier ones: merge {"a": 1} with {"a": 2} and you get {"a": 2}. Flip it off and the first value wins - {"a": 1} stays, because later dicts only fill in keys that don't already exist. There's no wrong answer; it depends on which source you trust more. Default-on means "the most recent dict is authoritative," which is usually what you want when layering defaults under overrides.
One honest caveat: this is a shallow merge. If two dicts both have a nested dict under the same key, the later one replaces the earlier wholesale rather than merging the inner fields. If you need deep merging, the pack's JsonMerge does recursive merging instead - reach for that when your data is nested.
How it works
It starts with dict(dict1), then applies each subsequent dict in order - update() when overwrite is on, fill-missing-only when it's off. The extra inputs (dict3 through dict32) are dynamically generated under the hood, which is why the node shows as many or as few ports as you need.
Inputs
dict1,dict2- required. Everything after is optional and dynamic:dict3…dict32.overwrite- true (default): later dicts win collisions. False: first dict keeps its values.
Output
merged_dict- the combined result,*-typed.
Install
Part of ComfyUI-YogurtNodes:
cd ComfyUI/custom_nodes
git clone https://github.com/yogurt7771/ComfyUI-YogurtNodes.git
cd ComfyUI-YogurtNodes
pip install -r requirements.txt
Or search "YogurtNodes" in ComfyUI Manager and restart. Under "Yogurt Nodes" → Logic.
Common issues
- "The merge lost my value" - collision, and
overwriteis on, so a later dict replaced it. Decide which source wins and setoverwriteto match. - "Nested dicts got clobbered" - shallow merge. Use
JsonMergefor deep merges. - "I plugged in a third dict and there's no port" - the optional inputs are dynamic; the node should show new ports as you connect them. If not, check for a recent node update.
For combining defaults with overrides, building a unified config from several sources, or assembling the full key set before a DictSubset extraction, this is the node. Just remember the collision rule and you're in good shape.
Inputs (33)
| Name | Type | Default | Description |
|---|---|---|---|
| dict1 | * | First dictionary | |
| dict2 | * | Second dictionary | |
| dict3opt | * | Additional dictionary 3 (optional) | |
| dict4opt | * | Additional dictionary 4 (optional) | |
| dict5opt | * | Additional dictionary 5 (optional) | |
| dict6opt | * | Additional dictionary 6 (optional) | |
| dict7opt | * | Additional dictionary 7 (optional) | |
| dict8opt | * | Additional dictionary 8 (optional) | |
| dict9opt | * | Additional dictionary 9 (optional) | |
| dict10opt | * | Additional dictionary 10 (optional) | |
| dict11opt | * | Additional dictionary 11 (optional) | |
| dict12opt | * | Additional dictionary 12 (optional) | |
| dict13opt | * | Additional dictionary 13 (optional) | |
| dict14opt | * | Additional dictionary 14 (optional) | |
| dict15opt | * | Additional dictionary 15 (optional) | |
| dict16opt | * | Additional dictionary 16 (optional) | |
| dict17opt | * | Additional dictionary 17 (optional) | |
| dict18opt | * | Additional dictionary 18 (optional) | |
| dict19opt | * | Additional dictionary 19 (optional) | |
| dict20opt | * | Additional dictionary 20 (optional) | |
| dict21opt | * | Additional dictionary 21 (optional) | |
| dict22opt | * | Additional dictionary 22 (optional) | |
| dict23opt | * | Additional dictionary 23 (optional) | |
| dict24opt | * | Additional dictionary 24 (optional) | |
| dict25opt | * | Additional dictionary 25 (optional) | |
| dict26opt | * | Additional dictionary 26 (optional) | |
| dict27opt | * | Additional dictionary 27 (optional) | |
| dict28opt | * | Additional dictionary 28 (optional) | |
| dict29opt | * | Additional dictionary 29 (optional) | |
| dict30opt | * | Additional dictionary 30 (optional) | |
| dict31opt | * | Additional dictionary 31 (optional) | |
| dict32opt | * | Additional dictionary 32 (optional) | |
| overwriteopt | BOOLEAN | true | Whether later dicts should overwrite earlier keys |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| merged_dict | * | — |