· 5 min read

Go 1.27 Put encoding/json on the v2 Engine. The Blog Post Landed November 4. Here Is What Changes and What Does Not.

On November 4, the Go team published a post saying encoding/json/v2 and encoding/json/jsontext are stable and generally available in Go 1.27. The release notes for 1.27, which shipped in August 2026, add that encoding/json itself is now backed by the v2 implementation. If you run a Go API as a one-person shop, the headline is a speedup. The footnote is a list of behavior changes that matter the moment you import v2 yourself.

What changed under your feet

According to the Go 1.27 release notes, the v1 package keeps its Marshal and Unmarshal behavior, though error message text may differ. v1 is implemented on top of v2 with a full set of compatibility options. The notes say v1 "will continue to be supported" and nobody is required to migrate. The Go 1 compatibility promise covers both packages, per the blog.

There is an opt-out: building with GOEXPERIMENT=nojsonv2 restores the original v1 implementation. The release notes say that flag is expected to be removed in a future release, so I would treat it as a bridge, not a plan.

What is faster

The blog says Marshal is roughly at parity with v1, sometimes slightly faster and sometimes slightly slower. Unmarshal is "significantly faster", with benchmarks showing improvements of up to 10x. The post does not give absolute numbers in the text, and the benchmark repository it points to is where the detail lives. I would read "up to 10x" as a best case on the right workload. Your own payloads are the only benchmark that counts, and a typical small request body will not look like a stress test.

The blog also describes a Kubernetes change, switching one recursive UnmarshalJSON to the new streaming method, that the post says improved performance by orders of magnitude. That is a case where a custom method was the bottleneck, which is a reminder to look for yours.

Where the behavior differs if you use v2 directly

The blog's list of differences between v1 and v2 is the part to read carefully. Invalid UTF-8 is an error in v2, where v1 accepts it. Duplicate object member names are an error in v2. A nil slice or map marshals as an empty JSON array or object, where v1 writes null. Unmarshal matches field names case-sensitively, where v1 is case-insensitive. The omitempty tag omits a field if it would encode as null, an empty string, an empty array or an empty object. And time.Duration reports an error on serialization unless you pick a representation.

Three of those can break a client you did not write: the null versus empty array change, the case-sensitive field matching, and the stricter handling of bad input. A mobile app that sent a lowercase key and has worked for two years is exactly the kind of thing that fails quietly.

The blog says many applications can migrate with no visible changes, and it documents per-behavior options so you can keep v1 semantics while moving to v2. The migration guide is at go.dev/doc/jsonv2-migration, which I did not read in full, so check it before you rely on my summary.

What I'd actually do

If I have not touched a single import, I would upgrade to 1.27, run the existing test suite, and compare response bodies from a handful of real endpoints before and after. For an API with no tests, that comparison is the whole test plan: capture ten real responses and ten real request bodies from logs, replay them against old and new builds, and diff them. An afternoon.

If I wanted the speed from v2 itself, I would move one endpoint at a time, starting with the one that parses the biggest bodies, and keep the v1 option set on until a diff shows nothing. I would treat the null to [] change as the first thing to grep for in the frontend.

I would not rely on GOEXPERIMENT=nojsonv2 to stay available.

Where this could be wrong

My read is that most small services will see nothing. If your API only serves your own frontend and your tests cover serialization, you can skip the diff and just upgrade. I could also be underestimating how often third parties send sloppy JSON, in which case the stricter defaults are a feature, not a bug, because they surface bad data you were silently accepting.

Author

Sources

Newsletter

The week, in one email.

The weekly summary of what happened and what it means for people who build alone. No spam, unsubscribe any time.

Form not showing? Subscribe on this page instead.

Related Posts