JSON Toolkit

JSON Parsing and Processing Library Comparison

Bottom line: Native APIs are fastest, tolerant parsers give offsets. Choose by three things: error location, whether the original text is preserved, and whether boundaries are explicit.

Intermediate~11 min readPublished 2026-10-30Updated 2026-10-30
JSON parsing and processing library comparison cover

Bottom line: classify the need first, then compare implementations — use native JSON.parse for read-only values, jsonc-parser when you need offsets or must preserve the original formatting, and add query or patch libraries only where required; lazy-load large libraries per page and drop unmaintained ones.

Every library claims to be "fast, small, and complete". What really separates them is how much information they can give you when something goes wrong.

1. Four categories by purpose

Category Representative libraries What it solves
Standard parsing JSON.parse / JSON.stringify Syntax ↔ object, speed first
Tolerant parsing + editing jsonc-parser, json5 Input with comments, errors precise to the offset, modifications that preserve formatting
Query jsonpath-plus, jsonpath Select nodes by expression
Mutation fast-json-patch, immer Generate/apply patches, immutable updates

Identify which category you are in first, then compare concrete implementations — otherwise it is easy to use a query library to do a parser's job.

2. Side-by-side comparison

Library Error location Tolerance (comments/trailing commas) Preserves original formatting Suitable scenarios
JSON.parse Message and position only (engine-dependent) ✗ ✗ Default parsing, API data
jsonc-parser Precise offset + error code ✓ ✓ (modify + applyEdits) Editors, configuration files
json5 Line and column information ✓ (more lenient) ✗ Reading JSON5 configuration
jsonlint Line and column information ✗ ✗ Reference only, not actively maintained
jsonpath-plus Expression syntax errors — — Querying by expression
fast-json-patch Operation-level errors — — Patch generation and application
lz-string — — — Compressing JSON into a URL

JSON.parse error messages vary widely across engines. V8 produces something like Unexpected token } in JSON at position 42, but whether the position is accurate depends on the engine version; jsonc-parser instead returns a stable structured { error, offset, length }, which is suitable for editor markers.

3. Four key decision points

3.1 Do you need offsets

If you are building an editor and want "click the error to jump to the corresponding line", you must have an offset. The test is simple: if your error message can only print "invalid JSON", users will have to hunt for it themselves.

import { parse, printParseErrorCode } from 'jsonc-parser';

const errors: Array<{ error: number; offset: number; length: number }> = [];
parse(text, errors, { allowTrailingComma: true, disallowComments: false });

if (errors.length > 0) {
  const firstError = errors[0];
  console.error(`${printParseErrorCode(firstError.error)} at offset ${firstError.offset}`);
}

3.2 Do you need to preserve the original text

Only reading values → any parser will do. "Change one field and keep everything else exactly as it was" → you must use an editing-style API, not "parse → change the object → serialize".

The latter loses: comments, key order (in some implementations), indentation style, numeric literal notation (1e3 becomes 1000), and escape forms (\u4e2d becomes the actual character).

3.3 Are the boundary behaviors explicit

Before choosing a library, check the documentation for three things:

  1. How duplicate keys are handled (keep the last one / raise an error);
  2. Whether large integers lose precision (most JS libraries do, because they all go through Number);
  3. The supported scope for BOM, comments, and trailing commas.

If there is no documentation, write a small sample and test it yourself. That is more reliable than reading the README.

3.4 Maintenance status

The risk of a JSON library is not missing features, but long-term neglect: nobody will ship security patches (prototype pollution, ReDoS) anymore.

4. Comparison with other languages

Language Standard library / mainstream library Key difference
JavaScript JSON.parse All numbers are double-precision
TypeScript Same as above + jsonc-parser / zod Types exist only at compile time
Go encoding/json float64 by default, use UseNumber() to preserve precision; json.RawMessage for deferred parsing
Java Jackson / Gson / Moshi With Jackson, watch out for the risk of enabling default typing
Python json / orjson parse_float=Decimal preserves precision; orjson is faster but does not support all types
Rust serde_json Strongly typed deserialization; the arbitrary_precision feature preserves precision
C++ simdjson / RapidJSON simdjson targets parsing throughput, RapidJSON is more general-purpose

When exchanging data across languages, the easiest things to trip over are still number precision and time formats; library choice can only mitigate them, not eliminate them.

5. Typical combinations

Option 1: Tool site (browser side)

Parsing and error location: jsonc-parser
Editor: CodeMirror 6 + @codemirror/lang-json
Query: jsonpath-plus
Patch: fast-json-patch
Share links: lz-string

The defining trait of this combination is that everything runs locally and no data is uploaded, which matches the privacy expectations of a utility site.

Option 2: Server-side API gateway

Validation: Ajv (compile the schema once, reuse it)
Parsing: native JSON.parse (together with a body size limit)
Deferred parsing of large fields: keep the raw string, parse only when needed

Do not introduce query/patch libraries into the gateway layer to implement business logic — that is the business layer's job.

Option 3: CLI and scripts

Pick fields: jq
Format conversion: yq / dasel
Interactive browsing: jless
Batch validation: ajv-cli

6. The real impact of bundle size and performance

  • jsonc-parser is very small and suitable for the main bundle;
  • json5 is slightly larger than jsonc-parser because it supports more syntax;
  • jsonpath-plus includes expression evaluation and is noticeably larger, so it should be lazy-loaded per page;
  • fast-json-patch is medium-sized and only needed when you have a comparison feature.

The optimization is straightforward: import dynamically per page, and do not put them in the first-screen chunk.

const { JSONPath } = await import('jsonpath-plus');

7. Checklist

  • [ ] Choose libraries by purpose; do not use a query library for parsing;
  • [ ] Use jsonc-parser when you need precise error locations;
  • [ ] Use editing-style APIs when comments and formatting must be preserved;
  • [ ] Test the three boundary behaviors in practice: duplicate keys, large integers, and BOM;
  • [ ] Watch the library's maintenance status and security advisories;
  • [ ] Dynamically import large libraries on demand.

FAQ

How do I pick a JSON library for my project size?

Small tools that only read API data can stay with native JSON.parse. Projects that need editor-grade error locations or must preserve the original formatting should use jsonc-parser. A server-side gateway needs only validation and parsing, leaving query and patch libraries to the business layer, while CLI scripts can use jq, yq, and ajv-cli directly.

Why does maintenance status matter more than feature count?

The real risk of a JSON library is long-term neglect, not missing features: nobody will ship security patches for prototype pollution or ReDoS. However complete the feature list, a stalled library leaves you patching it yourself. Treat maintenance and security advisories as hard criteria rather than comparing feature tables.

Should I use JSON.parse to change one field and keep comments and indentation?

No. Parsing, changing the object, then serializing loses comments, key order, indentation style, numeric literal notation (1e3 becomes 1000), and escape forms (\u4e2d becomes the actual character). Changing one field while keeping everything else intact requires an editing-style API such as modify and applyEdits in jsonc-parser.