JSON Merger with Conflict Reporting
Two config files, two API payloads, two versions of the same settings object: at some point one of them has to absorb the other. This page parses both documents in your browser, walks them key by key, and writes out a single merged JSON string with every disputed key listed in a conflict table.
Objects merge key by key, arrays follow the strategy you pick, and the side that keeps its value for scalar clashes is yours to choose. Keys that could poison a JavaScript prototype are skipped and named in the issues list, so you can see exactly what was left out of the result.
Merge Two JSON Documents With Conflict Reporting
Input A
The base document. Its keys are written into the output first.
Input B
The overlay document. Its new keys are added to the result.
Merge options
Only the unique mode reads this field.
Merged output
The merged JSON text lands here after a run. Copy it or download it as merged.json.
No conflicting keys.
| Path | A | B | Winner |
|---|
How It Works
Both panels are parsed with the browser's own JSON parser, and a parse error in either one stops the run with a message that names the side at fault. The merge then walks the two trees together: objects are combined key by key, arrays follow the chosen strategy, and every scalar clash is recorded with its path before the winner is applied.
- Paste both documents. Each panel takes one JSON text, and an empty panel or a parse error stops the run before anything is merged.
- Choose the winner and the array strategy. The winner pick decides which side keeps its value for scalar clashes, and the array pick decides how lists are joined.
- Set the identity field for unique mode. Unique mode compares object items by this field, such as id, and compares plain strings or numbers by their own value.
- Press Merge JSON. The output area shows the merged document, the conflict table lists each path with both values, and the summary line counts the merged nodes.
Before and After
The first pair runs the defaults: B wins the scalar clash and the tags list is replaced with the B list. The second pair switches the winner to A and concatenates the arrays, so the A items stay and the B items follow them.
A: { "service": "api-gateway", "port": 8080, "tags": ["core", "public"], "db": { "host": "db.internal", "pool": 10 } }
B: { "service": "api-gateway-v2", "timeout": 30, "tags": ["core", "internal"], "db": { "host": "db.internal", "replicas": 2 } } {
"service": "api-gateway-v2",
"port": 8080,
"tags": [
"core",
"internal"
],
"db": {
"host": "db.internal",
"pool": 10,
"replicas": 2
},
"timeout": 30
} winner for conflicting keys: A wins
array strategy: concatenate
identity field: id {
"service": "api-gateway",
"port": 8080,
"tags": [
"core",
"public",
"core",
"internal"
],
"db": {
"host": "db.internal",
"pool": 10,
"replicas": 2
},
"timeout": 30
} Use Cases
| Developer | Production | Workflow |
|---|---|---|
| Base config plus site overrides | Local environment folded into shared defaults | Two feature flag dumps joined into one |
| B wins keeps the newer values | A wins keeps the tested baseline | Concatenate joins rule lists end to end |
| Unique mode drops repeated ids | Conflict table skimmed before shipping | Skipped keys named in the issues list |
| Merged JSON downloaded as merged.json | Paths shown in dot notation | Every step computed inside the tab |
Common Mistakes
- Treating replace as a partial overwrite. Replace takes the whole B list for that key and drops the A list, so use keep when the first file's list is the one that must survive, and concatenate when both halves belong in the result.
- Running unique mode with an identity field the items do not carry. Unique mode reads the field you typed from every object item, and items missing that field are compared by their whole value, which rarely matches what you had in mind.
- Reading a conflict path as plain text. Paths use dot notation such as db.host, so a key that already contains a dot does not stand out visually; check the two value columns to confirm which key the row refers to.
- Trusting the merged output without skimming the conflict list. Every scalar clash is recorded, and a long list usually means the two files disagree more than expected, so settle the winner before the result is used anywhere.
Best Practices
- Leave the winner on B when the second panel is the newer export, and switch to A when the first panel holds the values you already tested. The winner pick applies to every scalar clash at once.
- Pick the array strategy for the job at hand. Replace suits settings where the new list is complete, keep suits lists you never touched, concatenate suits logs and rule sets, and unique suits collections built around ids.
- Set the identity field before choosing unique mode. A field such as id makes the dedup exact, and an empty box falls back to comparing whole items, which suits lists of plain strings or numbers.
- Skim the issues list after every run. Skipped keys are named with their full path, so a surprise entry tells you one of the inputs carried a dangerous field that was left out of the result.
Frequently Asked Questions
What does a deep merge actually do?
A deep merge walks both documents together and combines them node by node. When a key holds objects on both sides, those objects are merged instead of one replacing the other, so nested settings from both files survive. Keys that appear in only one document are copied across as they are.
What does the winner setting control?
The winner decides which side keeps its value when the same key holds different scalars, such as two different strings or numbers. B wins suits the case where the second panel holds the newer export, and A wins suits the case where the first panel holds the tested values. Every clash is listed in the conflict table whichever side you pick.
How do the array strategies differ?
Replace takes the B list for that key and drops the A list, while keep does the opposite and leaves the A list in place. Concat writes the A items first and then the B items. Unique joins the two lists and drops repeats it has already seen, comparing object items by the identity field you set, such as id, and plain strings or numbers by their own value.
What do the conflict paths look like?
Each path is the dot notation route to the disputed key, starting at the top of the document, for example db.host. The table row shows the path, the value each side held, and the winner that was applied. Long merged objects therefore produce paths you can read from top to bottom.
Is there a guard against prototype pollution?
Yes. Three key names, __proto__, constructor, and prototype, are never written into the merged output, whatever either input holds. Any key with one of those names is skipped and named in the issues list with its full path, so you can see that an input carried it.
Can I undo a merge?
No. The merge is computed on demand and nothing is stored, so there is no history to roll back. Keep both inputs as they are and run the merge again with different settings to produce a new result.
Does my data leave the browser?
No. Both panels are parsed by JavaScript running in this tab, and the merge happens in local memory. The result reaches you through the output area, the copy button, and a download link, and none of that touches a server. Closing the tab throws the inputs and the result away.