English

Developer tools · JSON formatter & validator

How JSON pretty-printing works: indent, whitespace and key order

· How it works

json developer-workflow validation

How JSON pretty-printing works: indent, whitespace and key order illustrated with JSON tokens and a precise validation boundary
Original ToolAcre vector illustration

Pretty-printing changes only insignificant whitespace, yet people worry it alters their data. This post explains what a formatter is allowed to touch, how indent depth is applied, and what happens to key order.

Same data, three different looks

Same data, three different looks — a compact API payload can occupy one line, expand with two spaces at each depth, or spread farther with four. The braces, brackets, names and values describe the same parsed structure in every version. Only line breaks and spacing between structural tokens differ. That distinction matters when reviewing formatter output: a larger diff is not automatically a data change, because indentation deliberately changes many bytes while leaving the resulting value intact.

ToolAcre offers two, four or eight spaces and a tab, then passes the chosen indentation to JSON.stringify. A short nested deployment record makes the comparison clear: regions remain in the same array order, booleans remain booleans and retry counts remain numbers.

Which whitespace JSON considers insignificant

Which whitespace JSON considers insignificant — RFC 8259 permits spaces, horizontal tabs, line feeds and carriage returns before or after structural characters. A formatter may therefore place a newline after `{`, spaces before a nested member and another newline before `}` without changing the value. Whitespace is not universally disposable, however. Once a double quote opens a string, every ordinary space belongs to that string's content and must survive formatting exactly as data.

The safest mental model is to separate token boundaries from string contents. Between a colon and a number, extra allowed whitespace is presentation. Between the letters of a quoted message, it is information. ToolAcre parses the source first and serializes the resulting value, so JSON.stringify chooses fresh whitespace around containers while preserving decoded string characters.

How an indent setting is applied

How an indent setting is applied — each nested container adds one copy of the selected indentation unit. A top-level property starts one level in; a property inside its object starts two levels in; an object inside an array adds another level. Closing braces and brackets return to the indentation of the container that owns them. The width therefore reflects structural depth rather than the length of a key, value or previous line.

Spaces create a fixed visual width in every editor, while a tab lets each viewer choose how wide one level appears. JavaScript also limits JSON.stringify indentation to ten space characters or the first ten characters of a supplied string, although ToolAcre exposes only practical presets.

Does formatting change key order?

Does formatting change key order? — ordinary pretty-printing does not intentionally sort object members. JSON objects are conceptually unordered collections, but JavaScript parsing and serialization use defined property-enumeration rules. Most non-integer keys therefore emerge in their input order, while integer-like keys can be emitted before other names. Consumers should never attach business meaning to member position, even when a formatter appears to preserve it consistently for familiar objects.

ToolAcre separates indentation from sorting. With sorting disabled, it serializes the parsed object directly. With sorting enabled, it recursively constructs objects whose keys are alphabetized before JSON.stringify runs; arrays keep their element order because reordering an array would change its meaning. This explicit option makes a reviewable distinction: whitespace-only output comes from pretty-printing, whereas a key-order diff comes from requesting canonical organization.

What a parse-and-reserialise formatter can change

What a parse-and-reserialise formatter can change — the parsed value survives, but its original spelling does not. A number written as `1.0` may return as `1`, and `1e3` may return as `1000`. An escaped printable character can reappear literally, while a literal character may be escaped when serialization requires it. Duplicate object names have already collapsed during parsing, so only the final property value remains available to the formatter.

These transformations explain why formatted output should not be treated as a byte-preserving document editor. Compare parsed values when semantic equivalence is the goal, and inspect textual diffs when original notation matters to a signing, hashing or auditing workflow. Very large integers deserve particular care because JavaScript numbers can lose precision before serialization.

Worked example: formatting a nested object

Worked example: formatting a nested object — begin with `{"service":{"regions":["sg","us"],"retry":{"count":3}}}` and choose two spaces. The opening root brace is followed by a newline. `service` receives two leading spaces, its child properties receive four, array elements receive six and the nested `count` property also receives six. Each comma ends one rendered member, and each closing delimiter aligns with the indentation level of its opening container.

Switching the same value to a tab changes only the prefix used for each level. Turning on key sorting can additionally place `regions` before `retry`, but the array still reads `sg` then `us`. A useful review checks the output in two passes: first confirm that nesting and array order represent the original value, then decide whether the chosen whitespace fits the repository.

What this does not cover

What this does not cover — key sorting is a separate normalization choice, and minification is the opposite presentation operation. Pretty-printing also never grants permission to reorder arrays: array position is data, so changing it can alter priority, chronology or program behavior. Nor does indentation make invalid source valid before parsing. Comments, trailing commas and JavaScript-only values must be corrected or handled by a parser for their actual format before a strict JSON formatter can serialize them.

Canonical JSON schemes go further than ordinary formatting by defining exact member ordering, number spelling and escaping for signatures or deterministic hashes. ToolAcre does not claim to implement such a canonicalization standard. It produces readable browser-local output using JSON.parse and JSON.stringify, with optional recursive key sorting.

Takeaway: pretty-printing is a whitespace transformation

Takeaway: pretty-printing is a whitespace transformation — its purpose is to expose structure without changing the represented value. Indentation width affects readability, review noise and local convention, not JSON validity. Whitespace inside strings remains data, array order remains significant and object-key sorting requires a separate explicit choice. Remembering those boundaries makes a formatter diff easier to assess and prevents cosmetic changes from being confused with semantic edits.

A parse-and-reserialize tool can still normalize number and escape spellings because it works from the value rather than the original token text. Review those cases when lexical fidelity matters, and avoid using ordinary pretty output as a canonical form for signatures. For everyday configuration and API inspection, select the indentation your team uses, leave sorting off unless it is wanted, format locally and validate the emitted text.