How to Deep-Merge JSON Objects Without Losing Data
Combining two configs by hand often clobbers nested data you meant to keep. This guide explains how deep merging actually works and how to merge JSON objects safely.
Combining two JSON documents sounds trivial until you actually try it. A shallow merge - the kind Object.assign or the spread operator gives you - simply overwrites any key that exists in both objects, which means a nested object in your override silently replaces the entire nested object in your base, wiping out sibling fields you never intended to touch. That is rarely what you want when you are layering environment settings on top of defaults.
This guide walks through what a proper deep merge does differently, how conflicting keys and arrays get resolved, and where teams usually get tripped up. You will also see how the JSON Merge tool applies these rules automatically in your browser, so you can combine configs or partial API responses without writing a recursive merge function yourself.
What does merging JSON actually mean?
Merging JSON means combining two or more JSON documents into a single object, key by key, so that the result reflects the union of everything each source contributes. When a key exists in only one source, it simply carries through unchanged. When the same key exists in more than one source, a merge strategy decides which value wins.
The important distinction is between a shallow merge and a deep merge. A shallow merge only looks at the top level of each object - if a key's value is itself an object, the later source's version replaces the earlier one wholesale. A deep merge recurses into nested objects and merges them too, so only the specific overlapping fields are replaced and everything else nested inside is preserved. JSON Merge performs a true deep merge, which is what most configuration and patching use cases actually need.
Shallow merge vs. deep merge
A shallow merge loses the sidebar setting; a deep merge keeps it.
Input
// base
{ "theme": "light", "layout": { "sidebar": true } }
// override
{ "theme": "dark", "layout": { "compact": true } }Output
// shallow merge result
{ "theme": "dark", "layout": { "compact": true } }
// deep merge result
{
"theme": "dark",
"layout": {
"sidebar": true,
"compact": true
}
}Why deep merging matters in practice
Most real-world JSON is layered on purpose. A base config holds sane defaults, and an environment-specific file overrides only what needs to change for staging or production. If merging that pair drops unrelated nested fields, you end up debugging a missing setting that was never actually removed on purpose - it was just clobbered by a naive merge.
- Configuration layering - defaults plus environment overrides should combine, not replace each other wholesale.
- Partial API responses - combining a summary payload with a details payload for the same resource should give you one complete object.
- Patch operations - applying a small change object to a larger document should touch only the fields the patch mentions.
- Predictability - a well-defined merge order means two people combining the same sources always get the same result.
How JSON Merge resolves conflicts
JSON Merge applies sources left to right, treating each object as a layer where later sources take priority. For any key that appears in more than one source, the value from the source with higher priority (the one added later) overrides the earlier one - but only after both values have been merged recursively if they are both objects. Non-object values, like strings, numbers, and booleans, are simply replaced outright since there is nothing to merge inside them.
Arrays are handled differently from plain objects because there is no single obvious way to combine two lists. That is why the tool lets you choose an array strategy: replace (the later array fully overwrites the earlier one), concatenate (both arrays' items are joined end to end), or merge by index (each array is walked position by position, deep-merging the elements at matching indices). Picking the right strategy for your data avoids surprises - concatenating tag lists usually makes sense, while replacing a list of feature flags usually does not.
Your configs never leave your browser
Deep merging is pure computation, so JSON Merge runs it entirely client-side. Config files with API keys, connection strings, or internal service URLs are merged locally - nothing is uploaded, logged, or stored on a server.
Step-by-step: merging two or more JSON objects
- Open JSON Merge and add your sources, starting with the base document and ending with your highest-priority override.
- Add any additional sources you need - each one merges in order, so priority increases with every document you add after the first.
- Choose an array strategy: replace, concatenate, or merge by index, depending on how your lists should combine.
- Run the merge and review the combined output, checking that nested fields you expected to keep are still present.
- Copy the merged JSON or use it directly as your final configuration or payload.
Because each source is validated before merging, a typo in one of your JSON fragments is caught immediately instead of producing a confusing partial result.
Common use cases for JSON merge
- Layering an environment-specific override file on top of a shared base configuration.
- Combining a user's saved preferences with your application's default settings.
- Merging two partial API responses that each describe part of the same resource into one object.
- Assembling a final config from several smaller fragment files stored separately in a repository.
- Applying a patch object - a small set of changed fields - onto an existing document without hand-editing it.
Common mistakes when merging JSON
Putting sources in the wrong order
Because later sources override earlier ones, adding your override file before your base file inverts your intent - the defaults will win instead of the environment-specific values. Always order sources from least to most important.
Assuming arrays always concatenate
Unlike object keys, arrays do not have an obvious default merge behavior. If you expect a list of allowed origins to grow when you merge in a new source but the strategy is set to replace, you will end up with only the later array's items and lose the earlier ones. Pick the array strategy deliberately rather than assuming.
Merging one invalid source
A single malformed source - a missing brace, a trailing comma - can make the whole merge fail or silently produce an incomplete result depending on the tool. Validate each fragment on its own first, for example with JSON Validator, before combining it with the others.
Confusing merging with comparing
Merging produces a new combined document; it does not tell you what changed between two versions. If what you actually need is to see the differences between a before and after config, use JSON Compare instead, and reach for merging only once you know you want to combine, not diff, the sources.
Best practices for merging JSON reliably
- Always order sources from base to override so the highest-priority document is added last.
- Decide your array strategy up front per field type - concatenate for lists that should grow, merge by index for parallel structured lists, replace for anything that should be fully swapped.
- Validate each source individually before merging so a single bad fragment doesn't derail the whole operation.
- After merging, run the result through JSON Formatter or inspect it in JSON Tree Viewer to confirm nested fields survived as expected.
- For sensitive configuration data, always merge with a tool that processes locally rather than uploading your files to a remote service.
Related tools
Compare two JSON documents and see a precise structural diff.
Recursively strip every null value from a JSON document.
Pretty-print JSON with configurable indentation and instant validation.
Recursively sort object keys alphabetically for stable, diffable JSON.
Related guides
A plain text diff on JSON is noisy and often wrong. This guide explains semantic JSON comparison, how added/removed/changed values are detected, and how to diff two documents without uploading them anywhere.
Null values sneak into JSON from ORMs, forms, and API serializers, bloating payloads and complicating merges. Here is how to remove them recursively - and when not to.
Minified JSON is unreadable and hard to debug. This guide covers how JSON formatting works, when to use it, common mistakes, and how to pretty-print JSON without uploading it anywhere.
Two JSON documents with identical data can look completely different in a diff if their keys are ordered differently. This guide explains why key order matters and how to normalize it instantly.