NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
Go modules
Last release 1 months ago
21 Aug 2026
Ships unpredictably
gaps range from 2 weeks to 2.0 years
Most releases are documented
notes for 10 of 12 stable releases
Nothing withdrawn
no release was ever pulled
11 years old
311 releases · first in 2016
Nothing published for this version
Nothing published for this version
🔒 Covered by ReqProof — L3 Assurance (123 requirements, 0 errors, 0 warnings)
Ported gjson's >'\\' single-comparison fast-skip to three hot loops. The trick skips all non-structural bytes (those > 0x5C) in one unsigned comparison per byte, reducing branch overhead.
| Payload | Before | After | Change |
|---|---|---|---|
| Small (190B) | 382 ns | 339 ns | -11.3% |
| Medium (2.4kB) | 3,899 ns | 3,141 ns | -19.4% |
| Large (24kB) | 20,788 ns | 20,114 ns | -3.2% |
Added tidwall/gjson (15.5k⭐) and bytedance/sonic (9.6k⭐) to the benchmark suite.
Large payload — the definitive ranking:
| Library | time/op | allocs |
|---|---|---|
| jsonparser | 20,114 ns | 0 |
| gjson | 22,756 ns | 2 |
| easyjson | 33,771 ns | 134 |
| sonic | 41,053 ns | 71 |
| ffjson | 59,063 ns | 144 |
| encoding/json | 130,565 ns | 147 |
jsonparser is the fastest across ALL payload sizes and the only zero-allocation parser.
Full changelog: CHANGELOG.md
One column per quarter.
Ported gjson's >'\\' fast-skip trick to three inner loops in parser.go:
stringEndConfig tail, blockEndConfig, and searchKeysConfig. The trick
uses a single unsigned comparison (byte > 0x5C) to skip all non-structural
bytes in bulk, reducing per-byte branch overhead.
| Payload | Before | After | Improvement |
|---|---|---|---|
| Small (190B) | 382 ns | 339 ns | -11.3% |
| Medium (2.4kB) | 3,899 ns | 3,141 ns | -19.4% |
| Large (24kB) | 20,788 ns | 20,114 ns | -3.2% |
Zero allocations maintained on all paths.
Added tidwall/gjson (15.5k⭐, path-based parser like jsonparser) and bytedance/sonic (9.6k⭐, SIMD-accelerated deserializer) to the benchmark suite.
Final leaderboard (large payload):
| Library | time/op | bytes/op | allocs/op |
|---|---|---|---|
| buger/jsonparser | 20,114 | 0 | 0 |
| tidwall/gjson | 22,756 | 28,672 | 2 |
| mailru/easyjson | 33,771 | 4,016 | 134 |
| bytedance/sonic | 41,053 | 31,368 | 71 |
| pquerna/ffjson | 59,063 | 4,822 | 144 |
| encoding/json | 130,565 | 4,432 | 147 |
jsonparser is the fastest across all payload sizes and the only zero-allocation parser.
🔒 Covered by ReqProof — L3 Assurance (123 requirements, 0 errors, 0 warnings, 0 open known issues )
Append// Append to an array without knowing its length
data, _ = jsonparser.Append(data, []byte(`"new_item"`), "items")Append(data, value, keys...) ([]byte, error) — clean array-append API. Works on top-level and nested arrays. Auto-creates missing paths as single-element arrays. No need for [N] path syntax.
| KI | Fix |
|---|---|
| KI-2 | ParseInt("-") now returns MalformedValueError (was returning 0, nil) |
| KI-3 | Disposition corrected to fixed (auto-coerce was implemented in v1.3.0) |
| KI-4 | Set([1,2,3], val, "[5]") now appends instead of returning KeyPathNotFoundError |
Zero open known issues. All 4 KIs are now status: fixed.
Append// Append to an array without knowing its length
data, _ = jsonparser.Append(data, []byte(`"new_item"`), "items")
Append(data, value, keys...) — appends value to the end of the JSON array addressed by keys. Addresses the top-level value when keys is empty; auto-vivifies a missing keyed path as a single-element array. Returns MalformedArrayError when the addressed value is not an array. Traced to SYS-REQ-009, SYS-REQ-110.ParseInt("-") now returns an error instead of (0, nil). One-line sign-only guard in bytes.go:parseInt (after stripping the sign byte, an empty remainder returns (0, false, false)).Set with an array-index path component under an object parent (and vice-versa) now auto-coerces the container type instead of emitting malformed JSON. (Disposition already set to fixed in v1.5.x.)Set on a top-level array-index beyond length now appends at the array's end (matching nested-array behavior under SYS-REQ-110) instead of returning KeyPathNotFoundError. Also cleans up trailing commas in malformed arrays.Zero open known issues. Every previously shipped known issue is now resolved and covered by ReqProof L3 Assurance.
🔒 Covered by ReqProof — L3 Assurance (123 requirements, 0 errors, 0 warnings)
Two optimizations found via ADHD-driven profiling + 10 parallel worktree experiments:
Fix stringEnd unbounded backslash scan — stringEndConfig was scanning the ENTIRE remaining parent document for backslashes instead of just the string body. Bounded to data[:firstQuote]. 128µs → 22µs (5.8x).
SWAR string scan — replaced two separate bytes.IndexByte calls with a single inline 8-byte SWAR loop checking for both " and \ simultaneously. 22µs → 21µs (additional 8%).
Methodology: Apple M4 Max (ARM64), Go 1.26.3, median of 5 runs. All comparison libraries updated. The
encoding/jsonbenchmark no longer uses ffjson-generated methods (fixed #126 in v1.3.1).
| Payload | jsonparser | encoding/json | easyjson | jsonparser advantage |
|---|---|---|---|---|
| Small (190B) | 382 ns / 0 allocs | 1,335 ns / 9 allocs | 312 ns / 4 allocs | 3.5x faster, 0 allocs |
| Medium (2.4kB) | 3,894 ns / 0 allocs | 10,564 ns / 18 allocs | 2,444 ns / 7 allocs | 2.7x faster, 0 allocs |
| Large (24kB) | 20,788 ns / 0 allocs | 134,123 ns / 147 allocs | 32,765 ns / 134 allocs | 6.4x faster, 0 allocs |
jsonparser is the fastest library overall on large payloads and the only zero-allocation parser.
Full changelog: CHANGELOG.md
stringEndConfig was scanning the ENTIRE remaining parent document for backslashes (bytes.IndexByte(data, '\\')) instead of just the string body. On a 24kb large payload this walked tens of KB per string. Now bounded to data[:firstQuote] (the string body only). 128µs → 22µs (5.8x).bytes.IndexByte calls (quote + backslash) with a single inline 8-byte SWAR (SIMD-Within-A-Register) loop that checks for both characters simultaneously. 22µs → 21µs (additional 8%).encoding/json benchmark no longer uses ffjson-generated methods (the #126 ffjson measurement bug was fixed in v1.3.1).| Payload | jsonparser | encoding/json | easyjson | Speedup vs encoding/json |
|---|---|---|---|---|
| Small (190B, Get) | 382 ns | 1,335 ns | 312 ns | 3.5x |
| Small (190B, EachKey) | 241 ns | — | — | 5.5x |
| Medium (2.4kB, Get) | 3,894 ns | 10,564 ns | 2,444 ns | 2.7x |
| Medium (2.4kB, EachKey) | 1,923 ns | — | — | 5.5x |
| Large (24kB) | 20,788 ns | 134,123 ns | 32,765 ns | 6.4x |
All jsonparser results: 0 bytes allocated, 0 allocations.
Nothing published for this version
🔒 Covered by ReqProof — L3 Assurance (123 requirements, 0 errors, 0 warnings)
var Lenient = jsonparser.Config{AllowSingleQuotes: true, AllowUnknownEscapes: true}
Lenient.Get(data, "key") // parses {'key':'value'} and unknown escapesSingle-quote support and lenient escape handling via an opt-in Config. Default stays strict (RFC 8259).
rp := jsonparser.NewReaderParser(file) // any io.Reader
rp.Get("users", "[0]", "name") // path-based access from a streamPath-based JSON access from an io.Reader — parse 10GB+ files without loading into memory. Buffers in 64KB chunks; memory bounded by the largest value.
EachArray, EachObject, EachArrayErr, EachArrayWildcard — canonical EachXxx pattern. Old XxxEach names kept for backward compatibility.
Full changelog: CHANGELOG.md
v1.5.0 extends the formal-verification coverage to 123 requirements (0 errors, 0 warnings) across all new APIs. Every new function is traced via source annotations, tested with MC/DC witnesses, and covered by the structure-aware fuzzer.
var Lenient = jsonparser.Config{AllowSingleQuotes: true, AllowUnknownEscapes: true}
Lenient.Get(data, "key") // parses {'key':'value'} and unknown escapes
AllowSingleQuotes — accept 'key':'value' alongside "key":"value" (JavaScript/Python-style). The same escape rules apply inside single-quoted strings.AllowUnknownEscapes — pass through unknown escape sequences (\`, \x) literally instead of erroring.Get, GetString, Set, Delete, ArrayEach, ObjectEach.rp := jsonparser.NewReaderParser(file) // any io.Reader
rp.Get("users", "[0]", "name") // path-based access from a stream
io.Reader — no need to load the entire document into memory.Get, GetString, ArrayEach.Canonical EachXxx pattern added alongside existing XxxEach names:
| New (canonical) | Old (kept for compat) |
|---|---|
EachArray |
ArrayEach |
EachObject |
ObjectEach |
EachArrayErr |
ArrayEachErr |
EachArrayWildcard |
ArrayEachWildcard |
EachKey, EachKeyErr, EachKeyWildcard already matched the pattern. All old names remain functional.
Nothing published for this version
New APIs (all backward-compatible)
ArrayEachErr — like ArrayEach but the callback returns error. Return io.EOF for graceful stop, any other error to abort. Resolves #53, #129, #176, #230, #255, #262.EachKeyErr — same pattern for EachKey.Escape(s string) []byte — RFC 8259 string escaping (inverse of Unescape). Produces a quoted JSON string literal.SetString(data, val, keys...) — Set with auto-quoted value. No more invalid JSON from forgetting quotes. Resolves #144, #158, #218, #270.GetArrayLen(data, keys...) (int, error) — count array elements without a callback. Resolves #175, #261.GetObjectLen(data, keys...) (int, error) — count object key-value pairs.GetUint64(data, keys...) (uint64, error) — uint64 variant of GetInt. Resolves #271.DeleteFound(data, keys...) ([]byte, bool) — returns whether the key was found. Resolves #229.EachKeyWildcard, ArrayEachWildcard, SetWildcard — [*] path component to iterate/set all elements. Resolves #112.
jsonparser.SetWildcard(data, []byte("true"), "users", "[*]", "active")ParsePath("$.users[0].name") → []string{"users", "[0]", "name"}CompilePath + CompiledPath — pre-compile and reuse with Get/Set/Delete/etc. Resolves #234, #251.
path, _ := jsonparser.CompilePath("$.person.name.fullName")
name, _ := path.Get(data) // reuse across callsImplemented by codex (gpt-5-codex) via codex exec. Proof coverage by ReqProof.
Full changelog: CHANGELOG.md
v1.4.0 adds 9 new backward-compatible APIs, each traced to a formal requirement and verified with MC/DC coverage. 121 requirements, 0 errors, 0 warnings.
Iteration with error/break control — resolves #53, #129, #176, #230, #255, #262
ArrayEachErr — callback returns error to stop early (io.EOF = graceful stop)EachKeyErr — same pattern for EachKeySafe string handling — resolves #144, #158, #218, #270
Escape(s string) []byte — RFC 8259 string escaping (inverse of Unescape)SetString(data, val, keys...) — Set with auto-quoted valueContainer accessors — resolves #175, #261, #271
GetArrayLen / GetObjectLen — count elements without a callbackGetUint64 — uint64 variant of GetIntDelete found signal — resolves #229
DeleteFound(data, keys...) ([]byte, bool) — returns whether the key was foundWildcard paths — resolves #112
EachKeyWildcard, ArrayEachWildcard, SetWildcard — [*] path componentJSONPath compiled paths — resolves #234, #251
ParsePath("$.users[0].name") → []string pathCompilePath + CompiledPath — pre-compile and reuse with Get/Set/DeleteFix Set/Delete input-buffer aliasing ( #209 , #141 ) — Set and Delete no longer corrupt the caller's input []byte when the slice has spare capacity. T
Fix Set/Delete input-buffer aliasing (#209, #141) — Set and Delete no longer corrupt the caller's input []byte when the slice has spare capacity. The append() call path was writing into the backing array beyond the returned slice. Now all mutation paths allocate a fresh buffer.
Fix EachKey array-index inconsistency (#232) — EachKey now descends into terminal array-index paths (e.g. "key", "[0]") consistently with Get. Previously EachKey returned empty where Get succeeded on the same path.
Fix benchmark measuring ffjson, not encoding/json (#126) — the benchmark payload types had ffjson-generated MarshalJSON/UnmarshalJSON methods, so the "10x faster than encoding/json" comparison was silently measuring ffjson. Now uses plain types with no generated methods.
| Bug | Proof gap | New gate |
|---|---|---|
| #209/#141 Set aliasing | No obligation said "Set must not mutate the input buffer" | New obligation no_input_mutation + assertInputUnchanged gate (snapshots input + backing-array capacity before every Set/Delete, verifies unchanged after) |
| #232 EachKey ≠ Get | No obligation said "EachKey must resolve paths identically to Get" | New obligation api_consistency + TestApiConsistencyEachKeyMatchesGet gate (random JSON + paths, asserts EachKey result == Get result) |
| #126 benchmark ffjson | Proof didn't cover the benchmark suite | Benchmark honesty lint: verifies no benchmark type implements json.Marshaler/json.Unmarshaler |
Contributed by codex (gpt-5-codex) via codex exec.
v1.3.1 fixes 3 bugs that escaped the initial proof review, with new proof gates to prevent recurrence.
Set and Delete no longer corrupt the caller's input []byte when the slice has spare capacity. All mutation paths now allocate a fresh buffer.EachKey now descends into terminal array-index paths consistently with Get.| Bug | Proof gap | New gate |
|---|---|---|
| #209/#141 Set aliasing | No obligation said "Set must not mutate the input buffer" | New obligation no_input_mutation + assertInputUnchanged gate |
| #232 EachKey ≠ Get | No cross-API consistency obligation | New obligation api_consistency + differential gate |
| #126 benchmark ffjson | Proof didn't cover benchmarks | Benchmark honesty lint |
🔒 Formally verified by ReqProof
jsonparser v1.3.0 is the first Go library proven to L3 assurance by ReqProof — a git-native requirements-engineering and formal-verification platform. Every public API is traced to a formal requirement, every requirement is tested with 100% MC/DC coverage, and the entire parser is fuzzed by a custom structure-aware JSON fuzzer at 250k inputs/sec.
The proof review caught 7 real bugs that years of community use, OSS-Fuzz, and standard fuzzing had missed.
Read the root-cause analysis →
Thank you to @c-tonneslan, @Solaris-star, @trevorprater, and OSS-Fuzz for the reports and contributions.
jsonparser v1.3.0 is the first Go library proven to L3 assurance by ReqProof, a git-native requirements-engineering and formal-verification platform. The entire codebase is now covered by:
encoding/json differential harnesses.The proof review found and fixed 7 real bugs that years of community use, OSS-Fuzz, and standard fuzzing had missed. Read the root-cause analysis →
jsonparser serves as the reference case study for ReqProof — learn more at reqproof.com.
Fix Delete panic on malformed input with leading comma (OSS-Fuzz 4649128545288192)
Delete panicked with index out of range [-1] on inputs like ,{"test":1{}.
The data[prevTok] dereference is now guarded.
Fix empty-string key-component panics (8 sites)
Get, GetString, GetInt, GetFloat, GetBoolean, GetUnsafeString, Set,
Delete, EachKey panicked with index out of range [0] when a key path contained
an empty string (""). All 8 unguarded keys[i][0] dereference sites are now guarded
with len(...) > 0. Found by the structure-aware hazard sweep.
Reported by @c-tonneslan (#284).
Fix Set data loss on scalar arrays (#267)
Set on an array-index path beyond the current length silently overwrote the array
instead of appending. Set({"a":[1,2,3]}, 99, "a", "[9]") now returns {"a":[1,2,3,99]}
instead of {"a":[99]}. Reported by @Solaris-star (#286).
Fix Set malformed-JSON output on cross-type paths
Set with an array-index path component under an object parent (e.g. Set({}, 9, "[5]"))
produced invalid JSON ({[9]}). Set now auto-coerces the container type to match the
path, always producing valid JSON output.
Fix Delete trailing-comma malformation
Delete left a dangling trailing comma in the output when the deleted element was
followed by JSON whitespace (space/tab/LF/CR) and a comma. Found by the structure-aware
path-mutation fuzzer.
Fix ArrayEach spurious callback on non-array root
ArrayEach on a non-array root value (e.g. ArrayEach({"a":1}, cb)) invoked the
callback with a spurious element before returning an error. The callback is no longer
invoked; a clean error is returned immediately.
Fix lone-Unicode-surrogate mishandling in Unescape
ParseString on a string containing a lone high surrogate (e.g. \uDB29 without a
following low surrogate) synthesized a bogus non-BMP code point from the following
literal bytes. Now substitutes U+FFFD (matching encoding/json behavior).
parseInt fast-path for short numbers — 22–37% faster on typical 1–10 digit integers. Numbers with ≤18 digits use direct int64 accumulation, bypassing the overflow-checked uint64 slow path. Contributed by @trevorprater (#285).
stringEnd SIMD fast path — 12× faster on no-escape strings, 4.5× faster end-to-end
on Get for string values. Uses bytes.IndexByte for the common case (no \ before
the closing ").
Nothing published for this version
Fix 2 bugs, remove 7 dead code blocks, add formal verification using ReqProof by @buger in #281
Updated travis to build for 1.13 to 1.15 by @janreggie in #225
Full Changelog: v1.1.1...v1.1.2
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Fix CVE-2020-35381 . PR #221
Fix CVE-2020-35381. PR #221
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Your coding agent can read these notes before it upgrades. Set up the MCP server →