jsonparser

A fast, allocation-free JSON parser for Go that reads values by key path without unmarshaling into structs.

Library
Go
vv1.6.1
5,651stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
80/100Excellent
Development Activity84
Maintenance68
Community68
Maturity60
Momentum40

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
78/100Good
Architecture80
Code Quality94
Innovation62
Learning Curve75

jsonparser is a Go library for extracting values from JSON payloads without knowing their full structure ahead of time or paying the cost of encoding/json’s reflection-based unmarshaling. Instead of decoding into a struct or a generic map[string]interface{}, it walks the raw byte slice and returns pointers to the requested keys directly, making it well suited to APIs with unpredictable or partially-relevant JSON responses.

The library has stayed dependency-free and API-stable for a decade while adding opt-in extensions: a Config type for lenient parsing (single-quoted strings, unknown escape sequences), a ReaderParser for streaming large documents from an io.Reader with a bounded sliding window, an EachKey batching API for extracting many paths in a single pass, and wildcard path support (EachKeyWildcard) for fanning out over arrays. It backs its performance and correctness claims with an unusually deep test suite spanning property-based tests, differential tests against encoding/json, native Go fuzzing, and a formal-verification/MC-DC audit pipeline.

What You Get

  • Key-path value extraction (Get, GetString, GetInt, GetFloat, GetBoolean) directly against a []byte payload, with array-index path segments like [0]
  • Zero-allocation string reads via GetUnsafeString for callers willing to tie the returned string’s validity to the underlying buffer
  • Batched multi-path extraction with EachKey, which scans the payload once and dispatches a callback per matched path instead of re-scanning per call
  • ReaderParser for streaming path-based lookups over an io.Reader with a configurable sliding-window buffer, so large documents don’t need to be loaded into memory at once
  • Opt-in lenient parsing via Config{AllowSingleQuotes, AllowUnknownEscapes} for JSON5-ish input, alongside the strict RFC 8259 default
  • In-place mutation helpers (Set, Delete) and iteration helpers (EachArray, EachObject, EachKeyWildcard) for arrays and objects addressed by key path

Common Use Cases

  • Extracting a handful of fields from large or unpredictable third-party API responses without maintaining a matching struct
  • High-throughput services where encoding/json’s reflection-based unmarshal cost is measurable, and only partial payload access is needed
  • Streaming large JSON documents from disk or network without buffering the entire payload in memory
  • Reading loosely-formatted or hand-edited JSON-like config files that use single quotes or non-standard escapes
  • Batch-extracting many known fields from the same payload in one pass via EachKey, instead of repeated Get calls

Under The Hood

Architecture The library is a single flat package built around a handful of core files rather than a layered or dependency-injected design, since it’s a leaf library with no framework responsibilities: parser.go holds the core token-scanning primitives (tokenEnd, findTokenStart, findKeyStart, internalGetConfig) that every higher-level function funnels through; config.go defines the Config struct and package-level Get/GetString/etc. as thin wrappers around a shared DefaultConfig instance, so the strict and lenient code paths stay unified; path_compiler.go translates JSONPath-style dotted strings into the ...string key-path arguments the rest of the API expects; wildcard.go builds array fan-out on top of the base Get/ArrayEach primitives rather than duplicating traversal logic; and reader_parser.go adds a streaming variant with its own sliding-window buffer that still calls into the same scanning helpers used by the byte-slice API. aliases.go keeps older names (ArrayEach, ObjectEach) as one-line forwarders to the canonical EachArray/EachObject. Because every public function depends on the same core offset-computation primitives, a change there has broad blast radius across the whole API surface — which the repo’s unusually heavy test and formal-verification layer is clearly built to guard against.

Tech Stack Pure standard-library Go with zero third-party runtime dependencies — go.mod declares go 1.13 and an empty go.sum, using only bytes, encoding/binary, errors, fmt, io, strconv, and strings, plus isolated unsafe use for zero-copy string views. Build and test tooling is a plain Makefile wrapping go test/go vet/go fmt inside a Docker container; a separate benchmark/ module with its own go.mod pulls in comparison libraries (ffjson, easyjson, gjson, sonic) purely for benchmarking, kept out of the main module’s dependency graph. CI runs Google OSS-Fuzz builds on every PR (cifuzz.yml) and, more unusually for a library this size, a formal-verification/MC-DC audit (reqproof.yml) against requirement specs under specs/ using a Z3 SMT solver.

Code Quality Test coverage is extensive relative to the library’s size — the majority of its Go files are test files, spanning ordinary table-driven tests, property-based tests, a differential suite comparing output against encoding/json, native Go fuzz targets, and dedicated regression tests pinned to specific historical issue numbers. Error handling is explicit and idiomatic: sentinel errors rather than panics, with callback-based iteration surfacing per-element parse errors through the callback signature instead of swallowing them. Naming is consistent (Get/GetString/GetInt/GetFloat/GetBoolean following one pattern, with older ArrayEach/ObjectEach names kept only as compatibility aliases). unsafe usage is isolated to two dedicated files behind a shared interface rather than scattered through the codebase, and go vet/go fmt are wired into the Makefile.

What Makes It Unique The core differentiator is avoiding both reflection and pre-declared structs — Get/EachKey/EachArray locate values by key path directly against the raw byte slice, with GetUnsafeString offering zero-allocation string views for callers willing to tie memory validity to the underlying buffer. EachKey batches multiple path lookups into a single scan rather than re-scanning per call, and more recent additions extend the same key-path model to streaming io.Reader input via ReaderParser with a bounded sliding window, plus opt-in lenient parsing for single-quoted or loosely-escaped input. None of these ideas are unique in isolation — byte-slice JSON scanning, unsafe string views, and streaming parsers all exist in other libraries — but the specific combination of zero dependencies, one-pass multi-key extraction, and a formal-verification/property-test harness layered on top of ordinary Go testing is a distinguishing engineering choice.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search