Go 1.27 marks the stable release of encoding/json/v2 and encoding/json/jsontext packages, a major update to JSON handling in the Go standard library. According to the Go Blog, these new packages address numerous behavioral flaws, API deficiencies, and performance limitations identified in the original encoding/json package over more than 15 years of use.

The original encoding/json package had several behavioral issues. Most notably, it accepted invalid UTF-8 sequences, contrary to RFC 8259 requirements, potentially introducing silent data corruption. The package also accepted JSON objects with duplicate member names, a vulnerability that could be exploited in security applications—a flaw previously documented in CVE-2017-12635. Additionally, encoding/json performed case-insensitive unmarshaling of JSON object member names to Go struct fields, which the source describes as a “surprising default” and potential security vulnerability.
API deficiencies included difficulty correctly unmarshaling from io.Reader without rejecting trailing junk, and options set on Encoder and Decoder types could not be used with Marshal and Unmarshal functions. Writing functions like Compact and Indent were limited to bytes.Buffer rather than more flexible interfaces like io.Writer.
Performance limitations stemmed from the MarshalJSON interface method requiring byte slice allocation and re-parsing of JSON output. The UnmarshalJSON method required complete JSON values be provided upfront, forcing the package to parse JSON twice. Despite operating on io.Writer or io.Reader, Encoder and Decoder types buffered entire JSON values in memory, with no corresponding token-writing API.
The Go team decided a new major version was necessary because these problems were inherent to the existing API and incompatible with Go 1’s compatibility guarantee. Rather than create a parallel namespace within encoding/json, they built encoding/json/v2 in a separate package.
The new packages separate “syntactic functionality” (encoding and decoding JSON grammar) from “semantic functionality” (mapping between JSON and Go values). The encoding/json/jsontext package handles syntax, while encoding/json/v2 assigns semantic meaning. This separation enables cleaner APIs and better performance characteristics.
Key facts
- encoding/json/v2 and encoding/json/jsontext are now stable in Go 1.27
- The new packages require valid UTF-8 and reject duplicate member names by default
- Case-insensitive unmarshaling and other behavioral flaws were addressed
- The new API separates syntactic (encode/decode) from semantic (marshal/unmarshal) functionality
- A new major version was necessary due to API changes incompatible with Go 1 compatibility promise
