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.

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:
- How duplicate keys are handled (keep the last one / raise an error);
- Whether large integers lose precision (most JS libraries do, because they all go through
Number); - 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-parseris very small and suitable for the main bundle;json5is slightly larger thanjsonc-parserbecause it supports more syntax;jsonpath-plusincludes expression evaluation and is noticeably larger, so it should be lazy-loaded per page;fast-json-patchis 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-parserwhen 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.