DEVELOPER TOOL
JSON Compare & Merge
Compare JSON, JS and TS files and merge single changes.
JSON A
pasted input
Nothing to read yet
JSON B
pasted input
Nothing to read yet
1 MiB per side · .json · .js · .ts · nothing leaves your browser
Waiting for both sides
What is JSON comparison?
Comparing two JSON documents means asking which keys and which values differ, rather than which lines of text differ. Those are not the same question. Two files can hold identical data and still disagree on every line because one is indented with tabs and the other with spaces, or because the keys were written in a different order. A text diff reports that as a wholesale rewrite; a structural comparison reports it as no change at all.
This tool parses both sides into data first and then walks that data, so what you get back is a list of properties. Each one carries its full path, the value on each side, and whether it was added, removed, changed, or changed type. A property nested six levels deep inside an array is reported at that exact position rather than as "this array is different".
That distinction is what makes the result actionable. Once a difference is a property rather than a region of text, it becomes something you can accept or reject on its own.
How to compare two JSON files
Paste a document into each side, or open a file with the file picker, or drag one onto either panel. Both sides are validated as you go, and the Compare button stays disabled until each side holds something that can actually be parsed. If it cannot, the error names the line and column and shows the offending line rather than a character offset you would have to count to.
After comparing you get a difference panel with a count, a set of filters and a search box. The filters narrow the list to added, removed, changed, type-changed or unchanged properties; the search box matches on both the property path and the values on either side, so looking for a value you remember works as well as looking for a key you know.
- Nested objects and arrays expand and collapse, so a large document opens at a readable depth.
- Identical subtrees are collapsed into a single row rather than listed property by property.
- A key containing a dot, such as "user.profile", is treated as one literal key and never split into a path.
- Arrays are aligned before they are compared, so inserting one item does not report every later item as changed.
How to compare JavaScript and TypeScript objects
Configuration rarely lives in a .json file. It lives in a config.js that ends in module.exports, or a config.ts that exports a typed constant, and comparing those usually means hand-copying them into JSON first. This tool reads them directly. It recognises a plain const declaration, export default, export const, module.exports and exports.name, along with TypeScript type annotations, as const and satisfies clauses.
The file is parsed, never executed. It is handed to a JavaScript parser which returns a syntax tree, and the tree is read looking for literal values. There is no eval and no dynamic evaluation of any kind, which is the only responsible way to handle a file somebody pasted in from a repository they do not control.
The consequence is that a file whose values are computed cannot be read, and that is the right answer rather than a gap. A property written as getUserName() has no value until something runs, so instead of guessing, the tool points at the line and says it contains an expression it cannot convert into comparable data.
How selective JSON merging works
Most diff tools offer one choice: take everything from the left, or everything from the right. That is rarely what you want. A staging config and a production config differ in a dozen places, and usually only two of them are the ones you meant to sync.
Here every difference carries its own pair of actions. Choosing A to B writes A's value into B at that path and changes nothing else; choosing B to A does the reverse. A global direction selector sets the default for the whole list, and an individual action still overrides it. You can also tick several differences and apply them together, with a confirmation step that lists exactly what is about to change and into which side before anything is written.
Added and removed keys are never resolved for you. A key that exists only in B is offered as "add it to A" or "remove it from B", and you pick; nothing is inserted or deleted on your behalf. The updated document appears in its own panel where it can be formatted, minified, copied or downloaded, and a reset returns both sides to exactly what you pasted.
Common developer use cases
The pattern is almost always the same: two versions of the same structured document, and a need to move some but not all of the difference between them.
- Reconciling environment configuration, where staging has picked up keys production still needs and production has values staging must not overwrite.
- Reviewing an API response against a recorded fixture to see which fields actually moved after a deployment.
- Merging translation files, where a new locale has keys the base locale lacks and stale keys it should drop.
- Checking a package.json or tsconfig.json against a template without losing project-specific settings.
- Auditing a feature-flag or settings document between two tenants before copying one flag across.
- Resolving a conflicted lockfile or config by hand when a three-way merge has produced something unreadable.
What is preserved, and what is not
When you download a side that came from a .js or .ts file, the surrounding file is rebuilt rather than replaced: the imports, the declaration form, the exported name, the TypeScript type annotation, a trailing as const, the semicolon and any comments above the object all come back exactly as they were, along with the indentation and quote style the file already used.
Some things cannot survive, and the tool says so rather than letting you find out later. Comments written inside the exported object are lost, because they belong to positions in the source rather than to the data. Numbers are normalised, so 0xFF is written back as 255 and 1_000 as 1000. A key introduced by a merge is placed next to the neighbour it had on the side it came from rather than at a position it never occupied. If the original structure cannot be rebuilt safely at all, the download falls back to JSON and tells you why.
Everything runs in your browser. The documents are parsed, compared and merged locally; they are not uploaded, not stored, not written into the page address and not sent to any server. That also means nothing survives a reload, so keep the result before you navigate away. Normal site analytics still apply to the page itself, as they do everywhere.
JSON compare and merge questions
No, and it cannot. The file is given to a parser, which returns a syntax tree, and the tool reads literal values out of that tree. There is no eval, no new Function and no dynamic import of your code anywhere in the path. A file whose values are produced by calling a function is reported as containing dynamic expressions, with the line and column, rather than being executed to find out what those values would be.