We've all been there: It's Friday at 4:55 PM. You just need to merge two simple .json config files for deployment.

"This will take 30 seconds," you whisper — a naive lie to yourself.

Flash forward 3 hours later: You're staring blankly at a screen full of missing commas, silently questioning your life choices. 💀

Here is the tragic 3-act story of every developer who has ever tried to merge JSON files by hand.

Act I: "I'll just use Object.assign()!"

You open config.old.json and config.new.json. You want to update an endpoint while keeping your default timeout settings.

const target = { api: { endpoint: "/v1", timeout: 5000 }, features: { darkmode: true } }; const source = { api: { endpoint: "/v2" } // missing timeout! }; // Shallow merge using Object.assign(): const result = Object.assign({}, target, source); console.log(result); /* Output: { api: { endpoint: "/v2" }, // ❌ timeout: 5000 is GONE! features: { darkmode: true } } */ 

The Pain: Because Object.assign() and spread operators perform a shallow merge, the top-level api object was completely overwritten. Your timeout key was wiped out silently, your dev build crashed, and your coffee is now freezing cold. 🪦

Act II: "I'll use an online merger!"

Desperate, you open Google and paste your internal API configurations and localized client settings into the first online-json-merger-free.com site you find.

Suddenly, a cold sweat hits you:

"Wait... did I just send our production database keys and API tokens to a server hosted in someone's basement?" 😳

The Paranoia: You spend the next hour rotating secret tokens and auditing git commits just to be safe.

Act III: Salvation (The 100% Local Deep Merge)

To save your Friday nights and preserve your sanity, here are two simple solutions that actually work:

Option A: The Vanilla JS Deep Merge

If you're writing code, stop using { ...a, ...b } for nested JSON. Use a recursive merge strategy instead:

function isObject(item) { return item && typeof item === "object" && !Array.isArray(item); } function deepMerge(target, source) { let output = Object.assign({}, target); if (isObject(target) && isObject(source)) { Object.keys(source).forEach((key) => { if (isObject(source[key])) { if (!(key in target)) { Object.assign(output, { [key]: source[key] }); } else { output[key] = deepMerge(target[key], source[key]); } } else { Object.assign(output, { [key]: source[key] }); } }); } return output; } // Now your nested keys survive! 🎉 const merged = deepMerge(target, source); console.log(merged.api.timeout); // 5000 

Option B: Use JoinJSON (Zero Server Uploads)

If you just want a fast visual tool to merge JSON files in 2 seconds without writing boilerplate or risking privacy, I built JoinJSON.

  • 🔒 100% Client-Side Privacy: All processing happens inside your browser's V8 engine. Zero bytes ever leave your machine.
  • 🧠 Smart Deep Merging: Intelligently combines nested properties without wiping out non-conflicting keys.
  • 🧹 Instant Validation: Highlights missing brackets, bad quotes, or trailing commas before they break your code.

🔗 Give your backspace key a break: https://www.joinjson.com/

💬 Over to you:

What is the most chaotic JSON syntax error or merge bug that has ever wasted your time? (Mine is definitely trailing commas inside arrays). Drop your horror stories below! 👇