> ## Content Index
> Fetch the complete content index at: https://huizhou92.com/llms.txt
> Use this file to discover other available public pages before exploring further.

# Go 1.26 Shipped Without JSON v2 — Here’s the Real Reason Why
- URL: https://huizhou92.com/go-1-26-shipped-without-json-v2-heres-the-real-reason-why/
- Published: 2026-02-12T04:24:20.000Z
- Updated: 2026-02-12T04:24:20.000Z
- Description: The most important standard library rewrite in Go’s history is still experimental — and that’s by design.
- Author: huizhou92
- Tags: #Migrated-1788833207488, #Import 2026-09-08 02:07

On February 10, 2026, Go 1.26 landed with a bang. The **Green Tea** garbage collector is now the default. The `go fix` tool got a comprehensive modernization overhaul. Cgo call overhead dropped by **30%**. Heap address randomization arrived for 64-bit platforms. It was, by any measure, a milestone release.

And yet, the feature many developers had been waiting for — `encoding/json/v2` — was conspicuously absent from the stable API. It remains behind the `GOEXPERIMENT=jsonv2` flag, still experimental, still not ready.

If you’ve been tracking this from the sidelines, you might be frustrated. **Five years** of development, and it’s still not done? But if you dig into the tracking issue [#76406](https://github.com/golang/go/issues/76406?ref=huizhou92.com) and the related proposal [#71497](https://github.com/golang/go/issues/71497?ref=huizhou92.com), the picture becomes clear: this delay isn’t about slow engineering. It’s about **API perfectionism**, a grueling **backward compatibility** challenge, and a **memory regression** that almost derailed the entire project.

Let’s break it down.

![](https://cdn-images-1.medium.com/max/800/1*WQWPDgsHgUod_pRb0J8-8Q.png)

### The Big Picture: Why JSON v2 Matters

The current `encoding/json` (let's call it v1) has served Go developers faithfully for over a decade. But its design flaws have been accumulating like technical debt in a startup that never refactored. Here's the short list:

- It **silently accepts invalid UTF-8** in JSON strings
- It **allows duplicate keys** without complaint
- Custom `Marshaler` implementations **can't access configuration options**
- There’s no way to **reject trailing data** after a valid JSON document
- The “streaming” API is largely a fiction — under the hood, it buffers everything

These aren’t minor annoyances. In production environments, they’re **security attack vectors** and **silent data corruption** risks. RFC 8259 compliance? Not quite.

JSON v2, led by **Joe Tsai** and **Daniel Martí**, is the most ambitious standard library rewrite since generics landed. It aims to fix all of the above — and deliver massive performance improvements along the way.

### A New Architecture: Syntax vs. Semantics

One of v2’s most elegant design decisions is the **strict separation** of JSON processing into two layers:

- **`encoding/json/jsontext`** — The syntactic layer. Handles pure JSON tokenizing, parsing, and encoding. No reflection, no Go types. Think of it as a high-performance JSON scanner.
- `**encoding/json/v2**` — The semantic layer. Maps between Go types and JSON data, built on top of `jsontext`.

This separation is powerful. If you only need to validate or transform raw JSON without touching Go structs, you can use `jsontext` directly — no reflection overhead, true streaming, minimal allocations.

Here’s how the two versions compare:

![](https://cdn-images-1.medium.com/max/800/1*mhDop60EF5oK9AY3hFeewA.png)

That last row is worth emphasizing. Libraries like **Sonic** (ByteDance) achieve blazing speed by leaning heavily on `unsafe`. JSON v2 reaches comparable performance **without compromising memory safety**. That's the standard library's promise: you don't trade correctness for speed.

![](https://cdn-images-1.medium.com/max/800/1*QljZFwNh5Ds7q0XdNZacCw.png)

### Why It Didn’t Ship: The Four Blockers

So if v2 is this good, why isn’t it in Go 1.26? The tracking issue [#76406](https://github.com/golang/go/issues/76406?ref=huizhou92.com) reveals four distinct battlefronts.

#### The “Forever API” Constraint

In Go’s standard library philosophy, once an API exits the experimental phase and enters `encoding/json`, it falls under the **Go 1 compatibility promise**. Forever. No take-backs.

Joe Tsai has been explicit about this: performance bugs can be fixed later, but **API design flaws can accumulate into decades of technical debt**.

The current audit is focused on `jsontext`'s public interface. As the foundation layer, its design must balance high performance with ergonomics — particularly around Token handling and optimal interaction patterns with `io.Reader`/`io.Writer`.

There’s also the contentious `time.Duration` debate. V1 serializes durations as **nanosecond integers** — widely adopted but terrible for cross-language interoperability. V2 leans toward Go-style strings like `"1h2m3s"`, but this has sparked fierce discussions about standardization. Neither camp is backing down, and the API signature remains in flux.

#### The “Perfect Fidelity” v1 Shim

Here’s the ambitious plan: once v2 lands, the Go team wants to **maintain only one codebase**. The existing `encoding/json` would become a thin wrapper (shim) around the v2 engine.

The catch? The v2 engine must perfectly replicate **every behavior** of v1 — including the bugs, the undocumented quirks, and the edge cases that thousands of production applications accidentally depend on.

> *For example, v1 has specific inconsistencies when handling pointer-receiver Marshalers on non-addressable values. Many existing applications unknowingly rely on this behavior.*

Replicating these subtle, hard-to-document behavioral regressions inside a fundamentally different engine is an extraordinary engineering challenge. The team is currently “burning down” the list of micro-behavioral deviations discovered through large-scale testing. Progress is steady, but the tail is long.

#### The Memory Regression Bomb: Issue #75026

This was the most alarming blocker. During testing in Go 1.25 and 1.26, issue [#75026](https://github.com/golang/go/issues/75026?ref=huizhou92.com) reported a **catastrophic memory-allocation regression** in specific map-serialization scenarios.

The numbers speak for themselves:

![](https://cdn-images-1.medium.com/max/800/1*T_O6T9fC4Hv-wyohbzpwsw.png)

[https://github.com/golang/go/issues/75026](https://github.com/golang/go/issues/75026?ref=huizhou92.com)

Yes, you’re reading that correctly. A **39x increase** in memory allocation for a common map encoding pattern.

Profiling revealed that **92.98%** of allocations were concentrated in `bytes.growSlice`, pointing to a severe buffer management defect when handling complex object trees or specific map structures. While the total number of allocations (`Allocs/op`) actually decreased, the per-allocation size exploded, putting enormous pressure on the GC.

If this regression had shipped as the default behavior for v1 users, it would have been catastrophic. Fixing these extreme-case allocation paths is currently the **highest priority work item**.

#### 4\. Ecosystem Maturity and the Union Type Debate

The JSON v2 project has been in development for **five years**. While it’s been validated in many production environments, it still needs broader ecosystem stress testing before becoming the default. The Project 50 tracker shows that out of 44 sub-tasks, roughly **18 remain open** or require further audit.

Additionally, there’s an ongoing debate about whether v2 should support **union** (sum) types for JSON deserialization. Some developers argue this is table stakes for modern JSON processing. The Go team’s position? Wait for a proper **language-level sum type proposal** (like [#57644](https://github.com/golang/go/issues/57644?ref=huizhou92.com)) to mature first, rather than baking a temporary, incompatible implementation into the JSON package.

This is classic Go pragmatism: don’t solve language problems at the library level.

### The Features That Make v2 Worth the Wait

Despite the delays, the experimental version already showcases features that will fundamentally change how we handle JSON in Go.

#### `omitzero` — Finally, Sane Omission Logic

`V1’s omitempty` has confused developers for years. Is `time.Time{}` empty? Is `false` empty? The answers are inconsistent and often surprising.

V2 introduces `omitzero`, which evaluates strictly against Go's **zero value** semantics and supports a custom `IsZero() bool` interface:

```go
type Event struct { 
    Name      string    `json:"name"` 
    StartTime time.Time `json:"start_time,omitzero"` 
    EndTime   time.Time `json:"end_time,omitzero"` 
}
```

This is particularly useful for **PATCH-style APIs** where you need to serialize only explicitly modified fields, without accidentally omitting fields that happen to hold a type’s default zero value.

#### `inline` and `unknown` — Flexible Data Modeling

Two new struct tags solve long-standing pain points:

- **`inline`**: Flatten a nested struct or map into the parent JSON object — without anonymous embedding. This is huge for APIs with dynamic key-value pairs.
- `**unknown**`: Designate a field (typically `map[string]jsontext.Value`) to capture all JSON members not defined in the struct. No more "double deserialization" overhead.

```go
type Config struct { 
    Version  int                          `json:"version"` 
    Name     string                       `json:"name"` 
    Extra    map[string]jsontext.Value    `json:",unknown"` 
}
```

#### `format` — Built-In Encoding Customization

The `format` option enables per-field customization for encoding:

- Custom Base64 or Hex encoding for `[]byte` fields
- Custom `time.Time` layout strings
- No more writing bespoke Marshaler/Unmarshaler implementations for common formatting needs

### Performance: The Benchmark Story

Based on the `jsonbench` evaluation suite, here's how v2 stacks up against the competition:

![](https://cdn-images-1.medium.com/max/800/1*RqjqI9iyJnlohyaitNyLJg.png)

The key insight: v2 achieves its performance gains through **iterative, linear parsing** rather than v1’s per-byte virtual function scanning. And it does this without a single `unsafe.Pointer`. That's not just fast — that's **responsibly fast**.

### The Road Ahead: When Will v2 Land?

Based on the current burn-down rate and the developer activity on [#76406](https://github.com/golang/go/issues/76406?ref=huizhou92.com), here’s the realistic timeline:

**First Half of 2026:**

1. **Fix Issue #75026** — Resolve the map encoding memory regression. This is the single most critical prerequisite.
2. **API Finalization** — Complete the audit of all public functions in `jsontext`, particularly the `Encoder`/`Decoder` state machine robustness in streaming scenarios.
3. **v1 Compatibility Layer** — Ensure all known v1 behaviors (including the “buggy” ones) have corresponding configuration options in the v2 engine.

**Go 1.27 (Expected August 2026):**

This is widely considered the **earliest and most likely window** for JSON v2 to drop the experimental flag and enter the stable standard library. The tree reopening for the 1.27 development cycle will be the critical signal to watch.

The Go team also plans to ship **modernization tools** alongside the v2 release. The revamped `go fix` will offer one-click migration from v1 to v2 defaults — not just string replacement, but type-aware transformations. For example, it could detect hand-rolled Base64 conversion logic and suggest replacing it with v2's `format:base64` struct tag.

![](https://cdn-images-1.medium.com/max/800/1*7eGlhXSCdG-Bqti-93mKcQ.png)

### Summary

1. **JSON v2’s delay is not a failure — it’s discipline.** The Go team refuses to ship an API with design flaws that would become permanent technical debt under the Go 1 compatibility guarantee.
2. **The architecture is sound.** The syntax/semantics split via `jsontext` and `v2` is an elegant and future-proof design.
3. **Performance is already proven.** Up to 10x faster unmarshaling, 3.6x faster marshaling — all without `unsafe`.
4. **The memory regression (#75026) is the key blocker.** A 39x allocation increase in map encoding must be resolved before v2 can become the default.
5. **Go 1.27 (August 2026) is the target.** The community should plan accordingly.

**For developers, here’s my practical advice:**

- **Internal tools:** Go ahead and try `GOEXPERIMENT=jsonv2` in non-critical systems. The `omitzero` and `unknown` features alone can simplify your code significantly. File bug reports — the team needs them.
- **Performance-sensitive apps:** If JSON unmarshaling is your CPU bottleneck, v2’s experimental build may already outperform v1 — and it’s safer than third-party `unsafe` libraries.
- **Public libraries:** Stick with `encoding/json` (v1) for now. The v2 API is still subject to breaking changes, and your users won't appreciate the instability.

JSON v2 will be the most significant library-level evolution in Go since generics. It doesn’t just make things faster — it closes a decade-long gap in Go’s data interchange standards compliance. As blockers are cleared one by one, a safer, faster, and more flexible era of JSON processing is coming with Go 1.27.

The wait is almost over. And it will have been worth it.

### References

- Go Issue [#76406](https://github.com/golang/go/issues/76406?ref=huizhou92.com) — JSON v2 Tracking Issue
- Go Proposal [#71497](https://github.com/golang/go/issues/71497?ref=huizhou92.com) — encoding/json/v2 proposal
- Go Issue [#75026](https://github.com/golang/go/issues/75026?ref=huizhou92.com) — Memory allocation regression in jsonv2 experiment
- Go Issue [#57644](https://github.com/golang/go/issues/57644?ref=huizhou92.com) — Sum types language proposal
- [Go 1.26 Release Notes](https://go.dev/doc/go1.26?ref=huizhou92.com)