JSON formatter benchmarks: which approach is fastest?

Comparing JSON.stringify, streaming parsers, and tree-diffing approaches across 1 KB to 1 MB payloads.

J
Jan Stepien·

JSON formatting seems trivial: take a string, parse it, pretty-print it. But when you build a formatter that runs in the browser on payloads ranging from a 50-byte API response to a 5 MB log dump, performance suddenly matters. A formatter that hangs the browser tab for 3 seconds is not a tool anyone will use twice. We benchmarked four approaches across five payload sizes to find where each breaks down — and what quickhelp.dev's JSON Formatter does differently.

The four approaches

1. Native JSON.parse + JSON.stringify: Parse the string to a JavaScript object, then re-serialize with JSON.stringify(obj, null, 2). This is the obvious baseline. It's synchronous, blocking the main thread for the full duration.

2. Regex-based formatter: Some formatters skip full parsing and instead manipulate the JSON string directly using regex — inserting newlines after {, [, , and before },]. This avoids the parse+serialize round-trip but produces incorrect output for edge cases (comma inside a string value, nested braces).

3. Streaming tokenizer (Web Worker): A streaming JSON tokenizer reads the input character-by-character, emitting tokens, and builds a formatted output string incrementally. Runs in a Web Worker, so the main thread is never blocked. Results stream back via postMessage chunks.

4. Virtual rendering (parse once, render lazily): Parse the JSON fully, then render the pretty-printed output into a virtualized list — only the visible lines are in the DOM. Crucial for very large payloads where the formatted string itself might be 100k lines.

Benchmark setup

All benchmarks ran in Chrome 124 on a 2023 MacBook Pro M2. We tested five payload sizes:

  • 1 KB — typical API error response
  • 10 KB — medium REST response (e.g., 10 records with nested objects)
  • 100 KB — large API response or config file
  • 500 KB — log file or bulk export
  • 1 MB — worst-case single-object payload

For each size we measured: parse time (ms), format time (ms), time until first visible output in the UI (ms), and whether the main thread was blocked during formatting (yes/no). Each measurement is the median of 10 runs after a warm-up pass.

Results

Approach 1: Native JSON.parse + JSON.stringify

PayloadTotal timeMain thread blocked
1 KB0.3 msYes (negligible)
10 KB2.1 msYes (fine)
100 KB18 msYes (noticeable)
500 KB94 msYes (jank)
1 MB210 msYes (visible freeze)

V8's native JSON parser is extremely fast — 1 MB in 210 ms total is impressive for a synchronous operation. The problem is that every millisecond blocks the main thread. At 500 KB users feel jank; at 1 MB the browser tab appears frozen for 200 ms.

Approach 2: Regex-based formatter

The regex approach is faster than native parse+stringify for small payloads (it skips the full parse step) but fails on correctness for strings containing ,, {, or } characters. We do not recommend it for production use — the speed advantage does not justify incorrect output on valid JSON. For the record, at 10 KB it runs in 0.8 ms; at 100 KB in 7 ms; it fails to correctly format 3/20 of our test inputs at each size.

Approach 3: Streaming tokenizer (Web Worker)

PayloadTime to first outputTotal timeMain thread blocked
1 KB12 ms15 msNo
10 KB14 ms28 msNo
100 KB15 ms140 msNo
500 KB16 ms680 msNo
1 MB17 ms1,380 msNo

The streaming approach delivers the best perceived performance: the UI is never frozen and the first lines appear within 15 ms regardless of payload size. Total time is slower than native at every size (the overhead of the Worker message passing and character-by-character tokenization adds up), but the user experience is far better — the formatter feels instant even on 1 MB payloads because the main thread is always responsive.

Approach 4: Virtual rendering

Virtual rendering shines not in raw formatting speed but in rendering speed. Naively inserting 100,000 formatted lines into the DOM takes 2–4 seconds just for layout. With a virtual list (only the visible ~50 rows are in the DOM), rendering is always under 20 ms regardless of payload size. Combined with approach 1 or 3 for the format step, this is the best overall architecture for large payloads.

What quickhelp.dev's formatter does

The quickhelp.dev JSON Formatter uses a hybrid: native JSON.parse + JSON.stringify for payloads under 100 KB (fast and synchronous is fine at this scale), and a Web Worker for larger payloads. The output is rendered into a virtualized textarea so the DOM never holds more than a few hundred rows regardless of input size. The result: instant feel for typical API responses, and no UI freeze even for 1 MB inputs.

Additional features run after the format step: key sorting (JSON.stringify with a custom replacer that sorts object keys alphabetically), minification (re-serializing with no indent), and validation (catching JSON.parse exceptions and surfacing the exact line and column of the syntax error via a regex on the V8 error message).

Key sorting performance

Alphabetical key sorting is done via a recursive replacer function. At 100 KB this adds roughly 12 ms over the baseline parse+stringify. At 1 MB it adds 95 ms — noticeable, but since key sorting is an explicit user action (not the default), this is acceptable. We do not sort keys by default because it changes the semantic order of fields, which can be misleading for ordered arrays of objects.

Conclusion

For JSON payloads under 100 KB, native JSON.parse + JSON.stringify is the right answer — it is the fastest correct formatter available in a browser. Above 100 KB, move formatting to a Web Worker and use a virtual list for rendering. Regex-based formatters are not correct and should be avoided. The biggest wins in perceived performance come from not blocking the main thread, not from algorithmic improvements to the format step itself.

Try the JSON Formatter — paste any JSON and get pretty-printed, minified, sorted, or validated output instantly. Runs entirely in your browser; nothing is sent to a server.

We use cookies to serve ads and measure traffic. Cookie policy · Privacy policy