{"slug": "moving-hatamoto-go-cms-to-encoding-json-v2", "title": "Moving Hatamoto Go CMS to encoding/json/v2", "summary": "Hatamoto's Go backend has fully migrated from encoding/json to encoding/json/v2, with any new v1 import in the backend now failing make check, the pre-push hook and CI, the company said. The change runs on hatamoto.dev today and ships to self-hosted installs in the next release, likely release candidate V1.0.9, built on Go 1.27 with no experiment flag set. REST, admin and MCP responses now return [] and {} instead of null for empty lists and maps, request bodies reject repeated member names, invalid UTF-8 and trailing data, and member names are matched case-sensitively, while webhook bodies, their HMAC signatures and host/WASM plugin bytes remain unchanged via pinned v1-compatible options.", "body_md": "# Moving Hatamoto Go CMS to encoding/json/v2\n\nHatamoto's backend now runs on Go's encoding/json/v2, and a new v1 import fails the checks. Empty lists come back as [], requests are stricter, and webhook and plugin bytes are unchanged.\n\nToday, Hatamoto moves fully to the newly announced [JsonV2](https://go.dev/blog/jsonv2)\n\nHatamoto's Go backend no longer uses the original `encoding/json` package. We moved the HTTP layer, content storage, the platform services, the plugin host and SDK, and the tests and tooling to `encoding/json/v2`. Any new v1 import in the backend now fails `make check`, the pre-push hook and CI. The change runs on hatamoto.dev today and ships to self-hosted installs in the next release. The likely release candidate is V1.0.9\n\nThe v2 package arrived in Go 1.25 behind `GOEXPERIMENT=jsonv2`. We build on Go 1.27, and our release build sets no experiment flag.\n\n## What API clients will see\n\nREST, admin and MCP responses return `[]` and `{}` for an empty list or map, where they used to return `null`. If your client checks for `null`, check for an empty list instead. The same goes for scripts that read `hatamoto ... --json` output, which also no longer escapes `<`, `>` and `&`, and neither does MCP tool output text.\n\nRequest bodies are stricter. A repeated member name, invalid UTF-8 or data after the JSON value is rejected. Member names are matched case-sensitively, which v1 never did: `Title` instead of `title` is usually ignored, and a few endpoints reject it with a 400.\n\n## What stays byte for byte the same\n\nWebhook bodies and their HMAC signatures are unchanged, and so are the bytes the host and WASM plugins exchange. Changing them would break any receiver that checks a signature, so they go through a pinned set of options that reproduces v1's output. The one difference: a plugin type with two fields that share a JSON name now fails to marshal instead of silently dropping both.\n\nSo the JSON move doesn't break plugins built with SDK 0.5 to 0.18. A separate change in the same release stops loading older plugins that request the removed write permissions, and a package whose `plugin.json` repeats a field name or spells one differently (`allowedHosts` for `allowed_hosts`) is now refused on install. Check the release notes before you update. SDK 0.19.0 needs Go 1.27 or newer.\n\nA migration normalises known mixed-case keys in stored JSON, and `hatamoto doctor json` reports any row that would fail a strict read. The JSON changes don't raise the rollback floor, since the previous release reads `[]` as well as it read `null`. Other changes in the same release have their own rollback steps, so read the release notes before you roll back.\n\n## How we keep v1 out\n\nBackend code goes through a small `internal/jsonx` package with named option sets for requests, stored data, responses, JSON inside HTML and pinned wire formats. The contributor guide says which to use.\n\nThree files still import v1 on purpose: two shims that read v1's legacy-compatibility options for the pinned set, and a test plugin frozen on the old encoder. Database migrations are exempt. Anywhere else in the backend, a v1 import fails the checks.", "url": "https://wpnews.pro/news/moving-hatamoto-go-cms-to-encoding-json-v2", "canonical_source": "https://hatamoto.dev/post/moving-hatamoto-to-encoding-json-v2", "published_at": "2026-11-06 01:29:38+00:00", "updated_at": "2026-11-06 01:50:58.906548+00:00", "lang": "en", "topics": ["developer-tools"], "entities": ["Hatamoto", "Go", "encoding/json/v2", "encoding/json", "hatamoto.dev", "SDK 0.19.0"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/moving-hatamoto-go-cms-to-encoding-json-v2", "markdown": "https://wpnews.pro/news/moving-hatamoto-go-cms-to-encoding-json-v2.md", "text": "https://wpnews.pro/news/moving-hatamoto-go-cms-to-encoding-json-v2.txt", "jsonld": "https://wpnews.pro/news/moving-hatamoto-go-cms-to-encoding-json-v2.jsonld"}}