Short answer: compare object members by name, not by the order in which they appear. Compare arrays by position unless the application contract says the array is set-like. If you ignore array order, use multiset semantics so duplicate counts still matter.
Reordered JSON appears everywhere: an API serializer emits fields in a new sequence, a configuration generator sorts keys, or a service returns tags in a different order. A text diff reports all of those movements. A semantic JSON comparison can remove the noise, but only after you define what “equal” means for the data.
The dangerous shortcut is to sort everything recursively. Sorting object names is often harmless for comparison. Sorting every array can change the meaning of ranked results, coordinates, workflow steps, queues, and any other sequence. The goal is not to produce the fewest differences; it is to report every difference that matters and suppress only presentation changes.
Compare a pair now: LiveParse compares parsed JSON by path, ignores object-member order, and lets you choose positional or unordered array matching. You can also decide whether number tokens such as 1 and 1.0 are distinct.
Object order and array order are not the same
RFC 8259, Section 4 defines a JSON object as an unordered collection of name/value pairs. These two documents therefore have the same members and values even though their source text differs:
{
"id": 42,
"status": "ready",
"active": true
}
{
"active": true,
"id": 42,
"status": "ready"
}
A semantic comparator groups object members by their decoded names and compares the associated values. It does not treat moving "active" to the first line as a data change. A text diff still should report that movement when exact serialization, review history, or a signed byte sequence is the thing being checked.
RFC 8259, Section 5, in contrast, defines an array as an ordered sequence of values. The index is part of how an item is addressed. The following arrays contain the same three strings, but they are not normally equal:
["gold", "silver", "bronze"]
["silver", "gold", "bronze"]
At index 0, the expected value is "gold" and the changed value is "silver". At index 1, the reverse is true. Ignoring that movement would hide a real ranking change. The same warning applies to latitude/longitude pairs, RGB channels, command arguments, pipeline stages, and chronological events.
Choose positional, set, or multiset semantics
An application can impose a set-like interpretation on an array even though JSON itself keeps the array ordered. Tags, enabled feature names, or a list of permissions are common candidates. Write that rule into the application contract or test description instead of assuming it from the shape alone.
| Comparison rule | What counts as equal | Good fit | Main risk |
|---|---|---|---|
| Positional sequence | Same length and an equal value at every index | Rankings, steps, coordinates, logs, queues | Reports reorderings even when the domain does not care |
| Set | Same distinct values, regardless of order or repetition | A domain that explicitly forbids or discards duplicates | Can hide duplicate-count changes |
| Multiset | Same values with the same number of occurrences, regardless of order | Order-insensitive data where repetition remains meaningful | Still unsuitable when position conveys meaning |
LiveParse's unordered option uses the multiset interpretation. That is a safer general definition of “ignore array order” because it does not silently erase repetitions. It matches equivalent whole values in any position while preserving how many copies occur.
Duplicate values still count
Consider an inventory batch in which each string represents one physical item. Reordering the scan does not matter, but quantity does:
["A", "A", "B"]
["B", "A", "B"]
A set-only comparison reduces both sides to {A, B} and incorrectly calls them equal. A multiset comparison reports that one "A" was removed and one "B" was added. The same principle applies to repeated numbers, strings, objects, arrays, booleans, and null values.
Do not confuse duplicate array values with duplicate object member names. RFC 8259 says names within an object should be unique for interoperability, but its grammar does not make repetition a syntax error. Parsers differ in how they expose repeated names. Treat a document such as {"role":"reader","role":"admin"} as an input-quality problem, not as an ordinary ordering question.
Be careful with nested and mixed-purpose arrays
An “ignore array order” switch often applies recursively. That produces the expected result when every relevant array is set-like, including nested collections. It is unsafe when one payload mixes unordered tags with an ordered history:
{
"tags": ["sale", "new"],
"checkoutSteps": ["address", "payment", "confirm"]
}
You may legitimately ignore order for tags, but not for checkoutSteps. LiveParse's array-order choice applies to the comparison as a whole. If the document mixes contracts, compare the relevant sub-array separately, keep positional comparison for the complete payload, or use a domain-specific test that applies a rule to selected JSON paths. Avoid globally sorting a production payload merely to make a test pass.
When records should be matched by ID
Arrays of objects introduce a third practical question: are records identified by position, by their entire value, or by a stable field? Suppose an API returns:
[
{ "id": "u1", "name": "Ana", "role": "reader" },
{ "id": "u2", "name": "Bo", "role": "editor" }
]
[
{ "id": "u2", "name": "Bo", "role": "admin" },
{ "id": "u1", "name": "Ana", "role": "reader" }
]
A positional diff produces changes at both indices. A whole-value unordered comparison matches Ana's unchanged record, but Bo's changed record appears as one removed object and one added object. A domain-aware comparator that matches by id can instead report the focused change u2.role: "editor" → "admin".
Match-by-ID is powerful, but it requires rules a generic JSON comparator cannot safely invent:
- Every compared record needs the chosen identity field, or the missing-ID behavior must be defined.
- IDs must be unique within each collection, or duplicate-ID matching becomes ambiguous.
- The ID type matters: the number
7and string"7"are different JSON values. - An ID change may mean “record renamed” or “old record removed and new record added”; only the domain can decide.
- Matching by ID intentionally hides record movement, so do not use it when display or processing order is significant.
LiveParse offers positional or whole-value unordered array matching; it does not ask you to nominate an ID field. For an automated domain test, validate identity first and then build maps explicitly:
function indexUniqueRecords(records) {
const byId = new Map();
for (const record of records) {
if (!Object.hasOwn(record, "id")) throw new Error("Missing id");
const key = `${typeof record.id}:${String(record.id)}`;
if (byId.has(key)) throw new Error(`Duplicate id: ${key}`);
byId.set(key, record);
}
return byId;
}
This sketch solves only identity indexing. The subsequent deep comparison still needs deliberate rules for numbers, nested arrays, missing fields, and duplicate object names.
Number lexeme versus numeric value
Even after you settle order, numbers need their own equality rule. A lexeme is the exact token written in the JSON source. The tokens 1, 1.0, and 1e0 are different character sequences, yet they denote the same mathematical value. Likewise, -0 and 0 can be treated as the same numerical quantity while remaining different source tokens.
{ "threshold": 1.0 }
{ "threshold": 1e0 }
Choose numeric-value comparison when the consumer cares only about the quantity. Choose exact-token comparison for serialization tests or contracts in which scale and spelling are evidence. Exact tokens are also useful when reviewing very large integers and long decimals: RFC 8259, Section 6 notes that implementations may impose limits on number range and precision, and describes the interoperability expectations associated with binary64 implementations.
A comparison tool should not round both inputs through a host-language number type before deciding equality if the original digits matter. LiveParse's Exact number tokens option keeps the source spelling visible. Turn it off when numerically equivalent JSON number forms should compare equal. Apply the choice consistently during unordered matching too: otherwise the number rule could change which array elements are paired.
Step by step: compare JSON while ignoring order
- State the contract first. Write down which arrays are sequences, which are set-like, whether duplicates matter, and whether numbers compare by token or mathematical value. If you cannot answer, keep arrays positional; it preserves more evidence.
- Make both inputs valid JSON. A semantic diff requires two parseable documents. If a trailing comma, comment, or unquoted name blocks parsing, fix the producer or use JSON Repair on a copy, then verify every proposed change.
- Open LiveParse JSON Compare. Paste or open the earlier/expected document in Left JSON and the newer/actual document in Right JSON.
- Choose number behavior. Leave Exact number tokens enabled when
1and1.0must differ. Disable it when equal mathematical JSON numbers should match despite notation. - Choose array behavior. Leave Ignore array order off for normal positional comparison. Enable it only when every array being assessed can safely use duplicate-preserving, unordered matching. For a mixed payload, extract the set-like branch rather than weakening the rule globally.
- Select Compare JSON. You can also use Ctrl/⌘ + Enter. The result summarizes additions, removals, changed values, and type changes, with paths back to the affected data.
- Review unmatched values, not just the total. In unordered mode, a modified object may appear as a removal plus an addition because the entire value no longer matches. If records have stable identity, follow up with an ID-aware application test.
- Record the chosen rules. A result is meaningful only with its options. In a bug report or test, say “object order ignored; arrays compared as multisets; exact number tokens enabled” rather than merely “JSON equal.”
Common approaches that give the wrong answer
Sorting serialized JSON strings
Line sorting is not structural comparison. It loses nesting context, mishandles multi-line values, and can confuse identical text appearing at different paths. Parse first, then compare values using the intended rules.
Recursively sorting every array
This makes sequence changes disappear and requires an arbitrary ordering for mixed JSON types and objects. It may also mutate the data being tested. Use unordered matching without rewriting the originals, and scope it to the contract that permits it.
Converting arrays to sets
A set erases multiplicity. That is correct only if the domain explicitly treats duplicates as meaningless or invalid. Multiset matching is the safer default for an order-insensitive comparison.
Using JSON.stringify equality
Comparing two serialized strings can report unequal solely because object members were inserted in a different order. Parse-and-reserialize normalization may also discard source distinctions, including number spellings, and ordinary object parsing may not preserve duplicate member names as separate evidence.
Assuming “no diff” proves a valid business object
Equality says the two inputs match under selected rules. It does not prove required fields exist, values fall within allowed ranges, IDs are unique, or the payload satisfies a schema. Comparison and validation answer different questions.
Frequently asked questions
Does JSON key order matter?
For the JSON data model, an object is unordered, so semantic comparison normally ignores member order. Source order can still matter to a text-level workflow, human review, or software that exposes ordering. Depending on it reduces interoperability, so distinguish exact serialization from object equality.
Does JSON array order matter?
Yes by default. An array is an ordered sequence under RFC 8259. Ignore its order only when an external application rule says the values form a set-like collection.
Are [1, 1, 2] and [2, 1, 1] equal when order is ignored?
They are equal under multiset semantics because each value occurs the same number of times. They are unequal positionally. Under exact-number comparison, a replacement of one 1 with 1.0 would also make the multisets different.
Are [1, 1, 2] and [1, 2, 2] equal as sets?
Their distinct-value sets are both {1, 2}, but their multisets differ. If duplicates represent quantity or repeated events, set comparison would hide one removed 1 and one added 2.
Should I sort arrays before comparing JSON?
Only if sorting is itself a documented normalization for that particular field and you can define a stable comparator. Unordered matching is usually clearer because it leaves the source untouched. Never sort arrays whose indices carry meaning.
Why does an unordered diff show an object as removed and added?
Whole-value multiset matching pairs equal objects. Once a property inside a record changes, the old and new objects are no longer equal, so they remain unmatched. Match-by-ID can create a more focused field diff, but only when the domain guarantees a suitable identity field.
Can I compare JSONL or NDJSON the same way?
JSONL and NDJSON contain one JSON value per physical line rather than one surrounding JSON array. Decide first whether line order is meaningful, then compare records with an identity or multiset rule appropriate to the dataset. Use the JSONL parser to inspect validity and records before applying a domain-specific comparison.
What if one side is invalid JSON?
Fix validity before deciding semantic equality. Preserve the original, make the smallest justified change, and do not let an automatic repair guess silently. LiveParse's JSON Repair shows proposed changes for review.
Primary reference
- RFC 8259: The JavaScript Object Notation (JSON) Data Interchange Format.
- RFC 8259, Section 4: Objects — object ordering and the interoperability guidance for member-name uniqueness.
- RFC 8259, Section 5: Arrays — arrays as ordered sequences.
- RFC 8259, Section 6: Numbers — JSON number grammar and implementation interoperability considerations.