Imagine you've been using a Swiss Army knife to prepare dinner for 15 years. It works — you can slice, dice, open cans — but every night you nick yourself on the same blade, and you can't sharpen one tool without dulling another. Go's encoding/json has been that knife since before Go 1.0: functional, ubiquitous, and full of paper cuts that the Go 1 compatibility promise made unfixable. The new encoding/json/v2 and encoding/json/jsontext packages, shipping stable in Go 1.27, are the purpose-built chef's kit. The core architectural move is a clean separation of concerns that v1 never had. The jsontext package handles pure syntax — encoding and decoding JSON tokens and values with no knowledge of Go types. The json/v2 package sits on top and handles semantics — the mapping between JSON and Go values via reflection. This isn't decorative layering. It's what makes streaming actually work: the new Encoder and Decoder operate token-by-token without buffering entire values in memory, eliminating the quadratic blowup that hit v1 when MarshalJSON or UnmarshalJSON methods recursively called Marshal or Unmarshal. The security and correctness defaults get meaningfully tighter. Invalid UTF-8 now errors instead of silently corrupting data. Duplicate object member names are rejected by default — a real attack vector previously exploited in the wild (CVE-2017-12635). Nil slices and maps marshal as empty arrays and objects rather than null, matching what most Go developers actually wanted and what downstream non-Go JSON consumers require. Case-insensitive unmarshaling, a surprising v1 default that created both security and performance problems, is gone. The performance story is structural, not just micro-optimization. The new MarshalJSONTo and UnmarshalJSONFrom interface methods operate directly on an Encoder or Decoder stream. This eliminates three categories of waste: the forced allocation of []byte returns from MarshalJSON, the double-parse where v1 had to find value boundaries before calling UnmarshalJSON, and the validation/reformatting pass v1 ran on every MarshalJSON output. The jsontext Token type is designed to represent arbitrary JSON tokens without allocation — a detail that matters enormously at scale. The API surface also cleans up accumulated friction. Options now work uniformly across Marshal, Unmarshal, Encoder, and Decoder — v1's Encoder/Decoder-only options that silently lost effect inside custom UnmarshalJSON methods are gone. The Compact, Indent, and HTMLEscape equivalents accept io.Writer instead of being locked to bytes.Buffer. Reading from an io.Reader no longer requires the Decoder workaround that fails to reject trailing junk. What makes this release notable beyond Go is the execution strategy. The team shipped v2 as a separate namespace (encoding/json/v2) rather than trying to patch v1 in place or creating a parallel MarshalV2/UnmarshalV2 within the same package. v1's RawMessage becomes a type alias to jsontext.Value, providing a clean migration bridge. The experimental phase ran for a full year with public feedback before stabilization — a deliberate validation loop that most standard library changes don't get. The limitation is scope: this is a fix to a known, well-characterized problem set, not a research contribution. Every issue addressed — duplicate names, nil marshaling, streaming performance, option plumbing — was documented in the community for years. The contribution is in the execution: getting the API right, maintaining backward compatibility via aliasing, and shipping it through Go's conservative release process. For the millions of Go programs that touch JSON daily, this is the most consequential stdlib change in years.