So, Where’s JSON v2?

Go 1.26 shipped, and everyone scrolling through the Release Notes is asking the same question: Where’s JSON v2?

The anticipation isn’t unfounded. The encoding/json package has served the Go community for over a decade—it’s the old friend Go developers work with every day. But this old friend has accumulated quite a few “bad habits,” and community complaints have never stopped.

So when the Go team announced a completely redesigned JSON v2, the general reaction was: Finally!

Then Go 1.26 landed, and JSON v2 is still sitting under the experimental encoding/json/v2 path. The timeline for going stable? Still “wait for announcement.”

The Go team isn’t flaking. They made a decision that surprised many but earned respect: don’t ship until it’s ready.

v1’s Pain Points

To understand why JSON v2 is taking so long, we need to look at what’s wrong with v1.

Think of JSON v1 as a ten-year-old kitchen—it seemed fine when first built, but over time, design flaws started showing up.

JSON v1’s pain points: like an old kitchen

Performance issues. When processing JSON, v1 buffers the entire JSON value in memory before parsing. It’s like laying out every ingredient across the entire counter before starting to cook. Fine for small data, but memory usage becomes unfriendly with large JSON responses.

API design issues. The json.NewDecoder(r).Decode(v) pattern looks normal, right? But it doesn’t reject garbage data at the end of JSON. When reading from a stream, trailing junk gets silently ignored. This can create security vulnerabilities when handling network requests.

// v1's hidden danger: no error, trailing garbage is ignored
var data MyStruct
json.NewDecoder(responseBody).Decode(&data)
// If responseBody is `{"name":"test"}garbage_data`
// v1 succeeds, garbage silently swallowed

Inconsistent behavior. v1 uses case-insensitive matching during unmarshaling. Your struct field is UserName, but username, USERNAME, or UsErNaMe in JSON all match. Sounds “smart”? It hurts performance (can’t use simple map lookups) and can be exploited by attackers to bypass security checks.

Here’s another headache: MarshalJSON and UnmarshalJSON interface methods sometimes don’t get called at all. When values come from maps or interfaces, the underlying value isn’t addressable, and these custom methods become useless. “Sometimes works, sometimes doesn’t” behavior drives debugging sessions crazy.

The Go team admits it themselves: many v1 behaviors weren’t well thought out initially and became legacy baggage. Want to fix them? Too risky—nobody knows how much production code depends on these “bug-level” behaviors.

v2: Starting Fresh

Facing these issues, the Go team made a decision: stop patching, design a completely new JSON library.

JSON v2’s design philosophy: better to have less than 100% API compatibility than to do things wrong.

The entire v2 architecture is split into two layers. jsontext handles pure JSON syntax—encoding, decoding, token parsing. This layer doesn’t depend on Go’s reflection mechanism, making it small and suitable for binary-size-sensitive scenarios (TinyGo, WebAssembly).

The second layer is the familiar json package, handling Go type to JSON conversion. It depends on jsontext and reflect, providing the Marshal and Unmarshal functions we use daily.

It’s like splitting an “all-in-one” supermarket into separate “produce market” and “kitchenware store”—fresh produce here, pots and pans there.

JSON v2 layered architecture: jsontext and json packages

Performance-wise, v2 promises true streaming. When reading JSON from an io.Reader, it only buffers the current token, not the entire JSON. For large file parsing, memory usage drops by an order of magnitude.

// v2 streaming example
import "encoding/json/v2"

// True streaming, only buffers current token
dec := json.NewDecoder(reader)
for dec.PeekKind() > 0 {
    var item MyStruct
    if err := dec.Decode(&item); err != nil {
        break
    }
    // Process each record, stable memory usage
}

For correctness, v2 defaults to rejecting invalid UTF-8 characters and duplicate JSON object keys (v1 allowed these, but RFC 8259 says this leads to “undefined behavior”). Security over performance.

So why didn’t Go 1.26 stabilize it?

Still Have Potholes to Fill

Performance regression. In early v2 testing, developers found a serious bug: when handling certain complex object trees or specific map structures, allocation counts dropped, but individual allocation sizes exploded. This puts enormous pressure on the garbage collector. If shipped with v1’s default behavior, the consequences could be bad.

Task list not cleared. According to Go’s official Project 50 tracker, about 18 of JSON v2’s 44 subtasks are still open or need further review (as of February 2026).

JSON v2 task progress tracker

These are key issues that could affect API design:

  • Union type support: Many developers think modern JSON processors should support deserializing union types. The Go team’s stance: “wait for a mature solution.”
  • Partial field updates: v2’s behavior isn’t finalized for scenarios where you only want to update certain struct fields.
  • Inlining and flattening: Flattening nested structs or maps into parent JSON objects—the API for this is still being discussed.

Backward compatibility. The Go team targets 95% to 99% of code migrating seamlessly. What about the remaining 1% to 5%? Clear migration paths and tool support are needed.

The Go team is developing a modernized go fix tool—not just string replacement, but type-aware code transformation. For example, it can detect your hand-rolled Base64 conversion logic and suggest switching to v2’s native implementation. This tool is still being polished.

Standard Library Isn’t Just Any Library

The Go team refuses to ship APIs with known defects.

The software industry has too many “ship first, fix later” examples. Rush features to release, deal with bugs later, technical debt piles up, eventually becoming “legacy systems” nobody dares touch.

JSON v2’s delay shows the Go team’s attitude toward the standard library: once something enters the standard library, the API must remain stable for a decade or more. Spending extra months or even a year polishing now is cheaper than carrying baggage for ten years.

Building a house meant to last a decade? Don’t rush to decorate before the foundation is solid.

Can I Use It Now?

Yes. It’s experimental, but already validated in many production environments.

If JSON processing is your performance bottleneck, or you really can’t stand some v1 behaviors, give encoding/json/v2 a try. Just remember:

  1. APIs may still change, you might need to modify code when upgrading
  2. Keep an eye on the Go 1.27 development cycle—that’s likely when JSON v2 will go stable
  3. If you encounter issues, report them on Go’s issue tracker to help the team discover and fix problems

FAQ

JSON v1 vs v2 comparison

Q: How much performance improvement does JSON v2 offer? A: Official tests show memory usage can drop by an order of magnitude in streaming scenarios. Actual improvement depends on your data structures and processing patterns.

Q: Can the current v2 experimental version be used in production? A: Yes, but note that APIs may change. Validate on non-critical business first and stay updated on version changes.

Q: Can v1 and v2 be used together? A: Yes. v2’s import path is encoding/json/v2, which doesn’t conflict with v1’s encoding/json.

Q: When will it be officially released? A: No official timeline. Go 1.27 (expected August 2026) is a possible window, but depends on completing remaining tasks.


Quick Reference: JSON v1 vs v2 Comparison

Issuev1 Behaviorv2 Improvement
StreamingBuffers entire JSON valueTrue streaming, only buffers current token
UTF-8 validationAllows invalid UTF-8Rejects by default, RFC 8259 compliant
Duplicate keysAllowedRejected by default, improved security
Case matchingCase-insensitiveConfigurable, stricter by default
Custom method callsInconsistentAlways called, predictable behavior
Trailing garbageSilently ignoredOptionally rejected
DependenciesRequires reflectjsontext layer has no reflection dependency

References