This is an adjunct proposal to #71497.

71497 proposes adding a new JSON API, consisting of encoding/json/v2 and encoding/json/jsontext packages. The existing encoding/json package is modified to use the new v2 implementation internally. Several new functions are added to encoding/json. See that proposal for details.

The proposed new API is implemented in github.com/go-json-experiment/json.

I propose that we merge the implementation in github.com/go-json-experiment/json into std immediately, enabled only when the GOEXPERIMENT=jsonv2 experiment flag is set.

When the jsonv2 experiment flag is not enabled, there will be no user-visible changes to std. The encoding/json package will exist exactly as it is now, and the proposed new packages will not exist.

When GOEXPERIMENT=jsonv2 is set:

  • The new encoding/json/v2 and encoding/json/jsontext packages will exist.
  • The encoding/json package will be implemented in terms of encoding/json/v2.
  • The encoding/json package will include the new APIs proposed in #71497.

The experimental API will not be bound by the Go compatibility promise and will evolve as updates are made to #71497.

If #71497 isn't approved in time for Go 1.25, we can either ship 1.25 with the GOEXPERIMENT guard or revert the experimental API in the 1.25 release. If #71497 is rejected, we'll remove the experimental package.

This proposal presumes that while there are still details being resolved, #71497 is on track for acceptance and we're happy with the general structure of the proposed API. Merging it into the main go repository prior to acceptance will make it easier for users to test out the new implementation.

Comment From: mvdan

Worth noting that one alternative would be to publish the entire code under e.g. x/exp/json once the proposal is approved, and use build tags such as //go:build go1.25 to forward the implementation (funcs, types, etc) to std once it lands there.

I see a few advantages to that mechanism: 1) Once the proposal is accepted and the API can be considered frozen, it lets downstreams start using it without waiting for the next Go release. This is particularly important for downstream library projects, as they tend to support two major Go versions. So if we were to merge into std for go1.25.0 being released in August 2025, many downstreams would have to wait until February 2026 to start importing it - even if just to implement new marshaler methods. 2) It skips the CUE_EXPERIMENT knob entirely, which could cause some transition pain over the next year or two, such as some projects not working correctly with (or without) the experiment enabled. 3) Placing the API under x/exp/json first allows us to delay adding it to std until late in the release cycle if we wish to, e.g. go1.25rc.1, reducing the chances that we need to do a big noisy revert if something goes wrong before then.

Comment From: seankhliao

given it's already in an external module, I'm not sure what another copy in x/exp would gain us?

Comment From: mvdan

x/exp is part of the Go project, which brings many benefits - Gerrit, CI, the rest of the reviewers and approvers. Plus, the import path blesses it as official to users, whereas https://github.com/go-json-experiment is pretty much just a third party org.

Comment From: seankhliao

an external module wouldn't benefit any existing users of encoding/json (which right now is ~all of them), without rewriting their imports, and reverting when it's released. Plus, existing users would be faced with multiple transitions from go-json-experiment -> x/exp -> json/v2 x/exp has the added negative of bringing in a lot of other experimental packages, which aren't fully deprecated yet, but all versioned together.

Comment From: neild

The primary purpose of this proposal is to make it easier to test the proposed new implementation of the encoding/json package. An x/ package doesn't help with that.

Comment From: aclements

This seems reasonable. @ianlancetaylor and I would like to at least look over #71497 because we start moving this forward. We plan to do that in the next week. Assuming it passes our sniff test, I think we can proceed with the GOEXPERIMENT=jsonv2 proposal.

Comment From: cespare

@ianlancetaylor and I would like to at least look over #71845

@aclements that's this one. Did you mean #71497 or possibly some other issue?

Comment From: aclements

This proposal has been added to the active column of the proposals project and will now be reviewed at the weekly proposal review meetings. — aclements for the proposal review group

Comment From: aclements

@ianlancetaylor and I looked over https://github.com/golang/go/issues/71497 and are happy enough with it to move forward with this proposal to expose it behind a GOEXPERIMENT.

Comment From: aclements

Is github.com/go-json-experiment/json in sync with #71497? It looks like it is from a few spot checks, but I want to make sure that "the API from #71497" and "the implementation at github.com/go-json-experiment/json are equivalent. :)

Comment From: aclements

Based on the discussion above, this proposal seems like a likely accept. — aclements for the proposal review group

The proposal is to merge the API of #71497 (currently implemented at github.com/go-json-experiment/json) into std, enabled only when GOEXPERIMENT=jsonv2 is set.

When the jsonv2 experiment is enabled: - The new encoding/json/v2 and encoding/json/jsontext packages will exist. - The encoding/json package will be implemented in terms of encoding/json/v2. - The encoding/json package will include the new compatibility APIs proposed in #71497.

When the jsonv2 experiment is not enabled, there will be no user-visible changes to std. The encoding/json package will exist and behave exactly as it does now, and the proposed new packages will not exist.

The experimental API will not be bound by the Go compatibility promise and will evolve as updates are made to #71497.

Comment From: aclements

No change in consensus, so accepted. 🎉 This issue now tracks the work of implementing the proposal. — aclements for the proposal review group

The proposal is to merge the API of #71497 (currently implemented at github.com/go-json-experiment/json) into std, enabled only when GOEXPERIMENT=jsonv2 is set.

When the jsonv2 experiment is enabled: - The new encoding/json/v2 and encoding/json/jsontext packages will exist. - The encoding/json package will be implemented in terms of encoding/json/v2. - The encoding/json package will include the new compatibility APIs proposed in #71497.

When the jsonv2 experiment is not enabled, there will be no user-visible changes to std. The encoding/json package will exist and behave exactly as it does now, and the proposed new packages will not exist.

The experimental API will not be bound by the Go compatibility promise and will evolve as updates are made to #71497.

Comment From: gopherbot

Change https://go.dev/cl/665796 mentions this issue: encoding/json: add json/v2 with GOEXPERIMENT=jsonv2 guard

Comment From: gopherbot

Change https://go.dev/cl/666935 mentions this issue: internal/fetch: include goexperiment.jsonv2

Comment From: cherrymui

@neild @dsnet Could you help write the release notes for jsonv2? (https://tip.golang.org/doc/go1.25#todo) Thanks!