Developer tools · JSON formatter & validator
Does key order matter in JSON? Ordering, equality and RFC 8785
· Background
json standards validation
The JSON specification calls objects unordered, but real parsers and serialisers usually preserve order, and signing schemes depend on it. This post untangles what the spec says, what implementations do, and how canonicalisation resolves the tension.
Same data, different bytes
`{"city":"Oslo","temp":4}` and `{"temp":4,"city":"Oslo"}` contain the same two names and values, yet their source bytes differ. Indentation can add many more textual differences without changing either parsed value. That is why “equal JSON” needs a comparison rule: are you comparing text, parsed objects, or a canonical representation defined by another protocol?
ToolAcre can remove whitespace noise by formatting both documents with the same indentation. It can also recursively sort object keys when that option is selected. Sorting changes member order deliberately but never moves array elements, because array position represents data. Neither ordinary formatting nor this optional sort produces RFC 8785 canonical JSON, so the output must not be substituted for a specified signing format.
What RFC 8259 says — an object is an unordered collection of name/value pairs, and implementations may expose order or not
RFC 8259 describes an object as an unordered collection of name/value pairs. Therefore, software that treats member order as the meaning of an ordinary JSON object relies on behavior outside that abstract model. Arrays are explicitly ordered, so `["draft","final"]` is not interchangeable with `["final","draft"]`. Object order and array order must never be normalized by the same rule.
The RFC also notes that libraries differ in whether they expose member ordering to callers. That warning is enough for portable design: do not encode priority or sequence by placing one object member before another. If sequence matters, represent it with an array or an explicit field. A formatter showing stable order is convenient for humans, but it does not turn position into a standards-level property of the object.
What this formatter actually does
With sorting disabled, ToolAcre parses the document and serializes the resulting JavaScript value. The output follows JavaScript property-enumeration behavior rather than preserving the original token stream byte for byte. Most ordinary string keys appear in familiar order, while integer-index-like names can be emitted ahead of other names. Number spelling and escape choices can also be normalized during reserialization.
With sorting enabled, the formatter builds new objects whose own keys are alphabetized at every nested object. For `{"z":{"b":1,"a":2},"items":[{"d":4,"c":3},"x"]}`, the object names become `items`, `z`; nested object names are sorted too; and the array still contains its object before `"x"`. Sorting objects inside an array does not mean sorting the array itself.
When byte order matters
Textual order matters whenever a process consumes exact bytes rather than the abstract value. A file hash, cache key, digital signature or line-based diff changes when members move or whitespace changes. That does not contradict the unordered object model; it means the surrounding process has chosen a byte representation as part of its input. The representation rules must then be explicit and shared.
For routine reviews, consistent indentation and optional alphabetical sorting can make changes easier to see. For cryptographic or protocol work, “looks stable” is not a contract. The producer and verifier must use the exact canonicalization algorithm required by their protocol before hashing or signing. If no algorithm is named, do not assume ToolAcre’s output will match another serializer across versions, runtimes or edge-case values.
Why key sorting is not RFC 8785
RFC 8785 defines the JSON Canonicalization Scheme for producing repeatable bytes from compatible data. Its work is broader than placing keys in alphabetical order. It specifies deterministic property sorting along with exact serialization behavior for strings and numbers and imposes constraints on the input model. Pretty indentation is not part of the canonical output, and locale-aware sorting is not an acceptable approximation.
ToolAcre makes no RFC 8785 claim. Its sort option is a readability feature layered over `JSON.parse` and `JSON.stringify`; it does not validate the I-JSON preconditions or replace the RFC’s serialization rules. A value such as `1e-7`, a key containing non-ASCII characters or an escaped string can reveal differences between a casual sorted formatter and a conforming canonicalizer. Use a tested JCS implementation when JCS is required.
Worked example: comparing two documents fairly
Compare `{"meta":{"rev":2,"owner":"Mira"},"steps":["cut","pack"]}` with `{"steps":["cut","pack"],"meta":{"owner":"Mira","rev":2}}`. Format both with two spaces and sorting disabled: whitespace becomes consistent, but the root and nested member orders can still differ. Parse both and compare their intended fields to establish value-level equivalence rather than declaring the raw text equal.
Turn on recursive key sorting and both examples render with the same object order while `steps` remains `cut` then `pack`. That is useful for a human diff, but it is still ToolAcre’s normalization, not RFC 8785 proof. If the second array were `["pack","cut"]`, sorting keys would correctly leave that difference visible because changing the array would change the represented sequence.
What this does not cover
Key sorting does not define deep equality for every application. Duplicate names are accepted by `JSON.parse`, which keeps the last value, so formatting can erase evidence that one source contained repeats. Large integers may already have lost precision in the JavaScript value. A domain may also treat selected arrays as sets, but ToolAcre cannot infer that rule and therefore never reorders arrays.
The formatter also does not compare schemas, apply defaults, normalize Unicode or decide whether two number representations are acceptable to a downstream system. Those are separate contracts. Use formatting to reduce presentation noise, a purpose-built structural comparison for value equality, and the specified canonicalizer for exact bytes. Mixing those jobs under the word “normalize” creates false confidence about what was actually compared.
Takeaway: order is insignificant to the model and significant to the bytes
Object member order does not carry meaning in the RFC 8259 data model, while array order does. Source bytes still record both order and whitespace, so hashes, signatures and text diffs observe distinctions that a value-oriented comparison may ignore. State which layer matters before choosing a tool: textual identity, parsed-value equivalence and protocol-defined canonical identity are three different questions.
ToolAcre supports the first two workflows only indirectly: consistent formatting clarifies textual differences, and recursive alphabetical object-key sorting can make human comparisons quieter. Arrays are never sorted. The result is not RFC 8785 canonical JSON and should not be signed as though it were. Preserve original input when lexical evidence matters, especially because parsing duplicate keys retains only the last value.