Skip to content

perf: cut normalized JSON parsing time by over 60% - #81

Open
RomainLanz wants to merge 1 commit into
11.xfrom
perf/json-normalization
Open

perf: cut normalized JSON parsing time by over 60%#81
RomainLanz wants to merge 1 commit into
11.xfrom
perf/json-normalization

Conversation

@RomainLanz

@RomainLanz RomainLanz commented Sep 1, 2026

Copy link
Copy Markdown
Member

Hey! 👋🏻

JSON normalization currently runs through a JSON.parse reviver. Node invokes this callback for every parsed value, even though the bodyparser only needs to transform strings. This makes normalized JSON parsing about three times slower on representative payloads.

This change keeps safeParse and its protections against __proto__ and constructor.prototype, but moves string normalization to an iterative post-parse traversal.

The traversal preserves the existing behavior for:

  • objects and arrays
  • nested values and empty keys
  • primitive roots in non-strict mode
  • disabled normalization options
  • malformed JSON and strict mode errors

It also avoids recursion during normalization.

Benchmark

Measured on Node.js 26.5.1 with the real parseJSON function and no profiler active. Each variant was warmed up before collecting 25 independent samples. The benchmark alternated the order of the variants between samples.

Payload Reviver min / median / max Post-parse min / median / max Median improvement
78,932 bytes 1,220 / 1,333 / 1,671 µs 359 / 409 / 575 µs 69.3% faster
1,064,458 bytes 15.41 / 17.93 / 22.84 ms 5.45 / 6.46 / 10.84 ms 64.0% faster

The benchmark includes request stream reading through parseText and raw-body, not only the JSON parsing step.

Compatibility

prepareJSONParserOptions now exposes an internal normalizer property instead of reviver.

This module is not part of the package export map, so public package consumers are unaffected. Applications importing the parser directly from the package sources or replacing options.reviver manually may need to update their code.

Tests

Added coverage for:

  • empty keys and their nested values
  • primitive root values in non-strict mode
  • prototype-poisoning properties
  • normalization at 10,000 levels of nesting

All 131 tests, lint, and TypeScript typechecking pass.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant