Nodes/ComfyUI-YogurtNodes/JsonMerge (Yogurt Nodes)
ComfyUI Node

JsonMerge (Yogurt Nodes)

Merge JSON objects the deep way — no more lost keys

By yogurt7771·Created 2 years ago·Updated 9 days ago· 1
JsonMerge (Yogurt Nodes)
  • json1
  • json2
  • json3
  • json4
  • json5
  • json6
  • json7
  • json8
  • json9
  • json10
  • json11
  • json12
  • json13
  • json14
  • json15
  • json16
  • json17
  • json18
  • json19
  • json20
  • json21
  • json22
  • json23
  • json24
  • json25
  • json26
  • json27
  • json28
  • json29
  • json30
  • json31
  • json32
  • merged_json

{...a, ...b} is a shallow merge - the kind that silently replaces whole nested objects instead of combining them. If you're stitching together configs or API payloads with overlapping structure, that's how you lose settings. JsonMerge does the deep version: it recurses into nested objects and merges key-by-key, so {"a": {"x": 1}} and {"a": {"y": 2}} become {"a": {"x": 1, "y": 2}} instead of one dict eating the other.

It's a logic node in the YogurtNodes pack (yogurt7771/ComfyUI-YogurtNodes), and one of the handiest of the JSON family. Every workflow that builds a request payload from parts - a base config plus overrides, a prompt template plus per-item metadata - eventually needs exactly this.

How it works

json1 and json2 are required, and then there are up to 30 optional inputs (json3json32), so you can merge a whole stack in one node instead of chaining. The merge itself is recursive: for dicts, keys are merged depth-first; for lists, elements are merged positionally (index 0 with index 0) where both exist, and appended where one is longer; for anything else, the second value wins. That last rule is the one to remember - on conflict, later inputs override earlier ones. Order your inputs so the highest-priority config comes last.

Both inputs can be objects or JSON strings; strings get parsed first, so you can merge a raw string straight in without a parse node.

Inputs that matter

  • json1 - base object.
  • json2 - the override, or just the second part. Required.
  • json3json32 - everything else. Add as many as you need; unused ones are ignored.

Output: merged_json.

Install

Same pack-wide routine - ComfyUI Manager (search "YogurtNodes") or:

cd ComfyUI/custom_nodes
git clone https://github.com/yogurt7771/ComfyUI-YogurtNodes.git
cd ComfyUI-YogurtNodes
pip install -r requirements.txt

Restart, find it under Yogurt Nodes / Logic. No extra dependencies.

Troubleshooting

  • "One of my nested dicts got replaced whole." That's what happens if you use a shallow merge node; this one shouldn't do it. If it did, check you actually wired into JsonMerge and not a dict-merge-with-overwrite. The tell: shallow merges replace {"a": {"x": 1, "y": 2}} with just {"a": {"y": 2}}.
  • List behavior isn't obvious. Positional merge means [1, 2] + [3, 4, 5] gives [3, 4, 5] (elements 0 and 1 overridden, element 2 appended) - not [1,2,3,4,5]. If you want concatenation, use the pack's ListConcat instead and set the key afterwards.
  • Ordering confusion. A merge is not commutative - json1 then json2 then json3 means later wins on conflicts. If you change input order you change the result. Keep the override (highest priority) last.
  • It doesn't mutate the originals. The node deep-copies both sides internally, so your json1/json2 inputs stay pristine for other branches. That's a feature - one shared config can safely feed a dozen merges.

The pattern to reach for: a defaults object in json1, workflow-specific overrides later, and the merged result feeding your API/LLM node. Config stays modular, nothing gets eaten, and the whole graph stays legible.

CategoryYogurtNodes/Logic

Inputs (32)

NameTypeDefaultDescription
json1*First JSON object
json2*Second JSON object
json3opt*Additional JSON object 3 (optional)
json4opt*Additional JSON object 4 (optional)
json5opt*Additional JSON object 5 (optional)
json6opt*Additional JSON object 6 (optional)
json7opt*Additional JSON object 7 (optional)
json8opt*Additional JSON object 8 (optional)
json9opt*Additional JSON object 9 (optional)
json10opt*Additional JSON object 10 (optional)
json11opt*Additional JSON object 11 (optional)
json12opt*Additional JSON object 12 (optional)
json13opt*Additional JSON object 13 (optional)
json14opt*Additional JSON object 14 (optional)
json15opt*Additional JSON object 15 (optional)
json16opt*Additional JSON object 16 (optional)
json17opt*Additional JSON object 17 (optional)
json18opt*Additional JSON object 18 (optional)
json19opt*Additional JSON object 19 (optional)
json20opt*Additional JSON object 20 (optional)
json21opt*Additional JSON object 21 (optional)
json22opt*Additional JSON object 22 (optional)
json23opt*Additional JSON object 23 (optional)
json24opt*Additional JSON object 24 (optional)
json25opt*Additional JSON object 25 (optional)
json26opt*Additional JSON object 26 (optional)
json27opt*Additional JSON object 27 (optional)
json28opt*Additional JSON object 28 (optional)
json29opt*Additional JSON object 29 (optional)
json30opt*Additional JSON object 30 (optional)
json31opt*Additional JSON object 31 (optional)
json32opt*Additional JSON object 32 (optional)

Outputs (1)

NameTypeDescription
merged_json*