JSON Merge
Deep-merge or shallow-merge two JSON documents. Choose whether arrays are replaced, concatenated or merged by index; every key and number is kept as written.
About JSON Merge
A deep merge combines two JSON documents all the way down: where both hold an object at the same key, the two objects are merged too, and JSON 2's value wins any other conflict. A shallow merge combines only the top level, so JSON 2's value replaces JSON 1's outright, as { ...a, ...b } and Object.assign({}, a, b) do in JavaScript. Arrays have no single rule, so the Arrays option chooses: JSON 2's array replaces JSON 1's, as in a JSON Merge Patch (RFC 7396); the two are concatenated; or they are merged by index, as lodash's merge does. JSON 1's keys keep their order, and the keys only JSON 2 has follow. Any key is read as a key, __proto__ and constructor included, and each number keeps its digits, so a 20-digit ID is not rounded and 59.90 stays 59.90. Notes under the result say where JSON 2 replaced an object or an array with a value of another type, and what a shallow merge dropped.
Built and maintained by Meet Shah · Last updated
What this tool is used for
- Layering an environment override file on top of a base configuration to see the effective result.
- Combining a default settings object with a user's saved preferences, then swapping the two to check which order your code needs.
- Building a single fixture from two partial API responses.
- Checking how your library merges, deep or shallow, and whether it replaces arrays, concatenates them or merges them by index.
- Producing a merged payload to send in one request instead of two.
Frequently Asked Questions
- What is the difference between a shallow and a deep merge?
- A shallow merge replaces whole top-level values, so a nested object in JSON 2 overwrites JSON 1's entirely, as
{ ...a, ...b }does. A deep merge recurses and combines nested objects key by key. Most surprises come from expecting deep and getting shallow, so a shallow merge here notes what it dropped. - How are arrays handled?
- There is no single rule, so the Arrays option chooses. Replace takes JSON 2's array, as
Object.assign, spread and a JSON Merge Patch (RFC 7396) do. Concatenate puts JSON 2's items after JSON 1's. Merge by index merges the items at each position, as lodash'smergedoes, so [1, 2] and [3] give [3, 2]. - How do I delete a key when merging?
- A merge cannot: a null in JSON 2 sets the value to null, as
Object.assignand lodash'smergedo. In a JSON Merge Patch (RFC 7396) null means remove instead, which is also why a merge patch cannot set a value to null. To remove keys, write the change as a merge patch and apply it with the JSON Merge Patch tool. - What is the difference from JSON Patch?
- A JSON Merge Patch (RFC 7396) looks like the document and is applied much like a deep merge, except that null removes a key and an array is replaced whole. JSON Patch (RFC 6902) is an explicit list of add, remove, replace, move, copy and test operations: more verbose, but it can set a null and change one array element.
- Which input wins on a conflict?
- JSON 2, the later one, by the same rule as
Object.assignand spread. Order therefore matters, and merging defaults over user settings rather than under them is a frequent bug. The Swap button exchanges the two documents, so the other order is one click away. - What happens when the two sides have different types for a key?
- JSON 2's value replaces JSON 1's outright: an object is not merged into a string. This is where silent data loss hides, since the result is valid JSON, so a note names each place where an object or an array in JSON 1 was replaced by a value of another type.
- Is a deep merge associative?
- Almost. Merging (A with B) with C matches merging A with (B with C), unless a place holds an object in A and C, or an array in both, and another type in B. With A
{"k": {"x": 1}}, B{"k": 5}and C{"k": {"y": 2}}, the first order gives{"k": {"y": 2}}and the second{"k": {"x": 1, "y": 2}}. - Are numbers and keys kept exactly?
- Yes. A merge through
JSON.parseandJSON.stringifyrounds 12345678901234567890 to 12345678901234567000, writes 59.90 as 59.9, and moves a key such as "10" to the front. Here each number is written as it was, JSON 1's keys keep their order with JSON 2's new keys after them, and__proto__is an ordinary key.
Common errors and gotchas
- Assuming every merge treats arrays alike.
Object.assignand a JSON Merge Patch replace an array whole, while lodash'smergemerges it by index, so there [1, 2] and [3] give [3, 2]. - Choosing a shallow merge and losing every nested key that JSON 2 did not mention.
- Assuming
nullin JSON 2 removes a key. A merge sets the value to null; only a JSON Merge Patch reads null as remove. - Diffing the merged file against one written by another tool, and reading a change of key order as a change of data. JSON parsers ignore key order.
- Merging through
JSON.parseandJSON.stringifyand trusting the numbers: a 20-digit ID is rounded, 59.90 becomes 59.9, and 1e400 becomes null.