New And Improved Formula! • The Applied Go Weekly Newsletter 2025-07-20
Your weekly source of Go news, tips, and projects
New And Improved Formula!
Hi ,
In this corner: JSON, the champion of sloppy data constructs. In the opposite corner: Go, the guardian of rigid data structures. In this uneven game, it looks like Go will turn to new tactics to keep the reckless JSON at bay. Stricter rules and new functions for the json
package are coming to Go 1.25, as an experiment first, but most Go experiments are so well-prepared that they usually stick around and turn into first-class Go members. More in the Spotlight section below, but first, here is an...
🌴 Important message: The newsletter goes into summer vacation (or winter vacation, depending on where you live) for the upcoming four weeks. But no worries, the issues continue to come, just shorter and in a different format. The full newsletter will be back on August 24th! 🌴
Keep up the good Go vibes!
–Christoph
Featured articles
How we tracked down a Go 1.24 memory regression across hundreds of pods | Datadog
Go 1.24 caused a 20% increase in memory consumption for Datadog's services. Read a story about a strange issue where system metrics were in disagreement with Go's runtime metrics, and how this journey ended in even lower memory consuption than before. A two-part article series by Nayef Ghattas.
The FIPS 140-3 Go Cryptographic Module - The Go Programming Language
Go 1.24 solves a major pain point for developers in regulated environments by building FIPS 140-3 cryptographic compliance directly into the Go standard library. Previously, users had to rely on unsupported solutions like Go+BoringCrypto. Now, compliance is as simple as setting GOFIPS140=v1.0.0
at build time. No code changes, no external dependencies, no performance penalties.
Gofakeit - Random Data Generator
Gofakeit reached 5,000 stars on Github. The author took this opportunity to write about the journey of Gofakeit, the community behind it, its future, and about the joy of maintaining an open source Go project.
Podcast corner
Fallthrough | Why You're Wrong About REST
How did the web evolve to its current state of 4.0, and did REST lose power along the way, or are we just using it in the wrong way? An analysis by Kris, Matt, Jame, and Steve.
See also the aftershow, a first-time compilation of the chats recorded while post-processing the episode recordings.
Cup o' Go | 🤌 The Gopherfather: Go 1.25, slog multihandlers, and more, capisce?
The Go world is relentlessly moving towards Go 1.25, and Cup o' Go is moving along with it, discussing Go 1.25 RC2, generic interfaces, new proposals, and oldies but goldies like urvfave/cli
.
Spotlight: New And Improved Formula! (JSON v2 in Go 1.25)
A while ago, when I opened another tube of my favorite toothpaste, my brain jumped into alert mode: The toothpaste looked entirely different from the one in the previous tube! Did the factory make a mistake and filled functionless filler material into the tube? Did criminals replace the toothpaste with poison to blackmail the company?
A few moments of web research later, it was clear that the company simply changed their formula. They just forgot or didn't bother to communicate that change on their tubes (like, with those blatant callouts with a neon-orange background saying something like "New and improved formula!"). Sigh.
The Go team, as always, acts much more careful and communicative about changes to Go. The upcoming json/v2
package is a great example: In Go 1.25, it is only available as an experiment (set GOEXPERIMENT=jsonv2
at build time to get all the json v2 goodness), and documentation is readily available at gotip
.
This is one of the first packages in the standard library to carry a "v2" tag (math/rand/v2
being the first one), which means breaking changes, and this begs the question: why?
Go and JSON aren't a great team. Go is a strictly typed language whereas JSON is kind of sloppy: dynamic typing, dynamic structures, ambiguous numbers, unstructured data, mixed-type arrays, etc. The original json
package has a difficult time catering to real-world use cases, and fixing or improving the package couldn't be done in a backward-compatible way, and so, the Go team decided to address the accumulated issues in a separate v2
package.
So what are the changes in v2
?
Let me summarize the changes here—briefly, because this is just a Spotlight and I already wrote this lengthy intro above just as if I was paid by word count. So here we go:
In a nutshell, Go's JSON package v2 introduces more secure and stricter defaults to remove or reduce many of the ambiguities that come with JSON marshaling and unmarshaling while maintaining backward compatibility through options.
Here are the key differences and their motivations:
Security improvements
- Stricter UTF-8 validation: v2 errors out on invalid UTF-8 instead of silently replacing it, to prevent data corruption
- No duplicate JSON keys allowed: v2 rejects duplicate object keys to prevent parsing ambiguities
- Less HTML escaping: v2 uses minimal escaping by default, to prevent unnecessary character mangling
More consistent behavior
- Case-sensitive field matching: v2 uses exact name matches instead of case-insensitive. This eliminates ambiguous field mapping
- Predictable
omitempty
: v2 omits fields based on JSON representation rather than Go zero values, which is more intuitive - Consistent null handling: v2 always zeros out values when unmarshaling JSON null
- Better merge semantics: v2 has clearer rules for when to merge versus replace during unmarshaling
Cleaner defaults
- Nil slices/maps: v2 marshals them as empty arrays/objects instead of null, which is a more natural JSON representation
- Byte arrays: v2 embraces the standard practice of using Base64 encoding rather than number arrays
- No deterministic map ordering: v2 allows natural map iteration; as Go maps have (intentionally!) no particular key ordering, this change results in better performance
- Stricter type validation: v2 reports structural errors at runtime instead of silently ignoring them
Breaking changes (for good reasons)
- Array length matching: v2 requires exact length match when unmarshaling arrays, to prevent data loss
- Limited
string
tag: v2 only allows it on numbers - No default time.Duration: v2 requires explicitly choosing a format; there's no default representation anymore
New functions
The above differences affect the functions that json
and json/v2
have in common. But json/v2
also comes with some new functionality. Core marshaling and unmarshaling gets these additional functions:
Marshal Functions
MarshalEncode(): Writes a Go value directly into a jsontext.Encoder
(a streaming encoder), allowing for streaming output without intermediate byte slice allocation
MarshalWrite(): Serializes a Go value directly to an io.Writer
, combining marshaling and writing in a single operation
Unmarshal Functions
UnmarshalDecode(): Reads and unmarshals the next JSON value from a jsontext.Decoder
, enabling streaming input processing
UnmarshalRead(): Reads JSON data from an io.Reader
and unmarshals it into a Go value, consuming the entire input until EOF
Marshaler/Unmarshaler Management
There are more functions, which I'll list only briefly here; feel free to peek into encoding/json/v2
for more information:
- Marshalers.JoinMarshalers(): Combines multiple marshaler functions
- Marshalers.MarshalFunc(): Creates type-specific marshaler from a function
- Marshalers.MarshalToFunc(): Creates type-specific marshaler using an encoder
- Unmarshalers.JoinUnmarshalers(): Combines multiple unmarshaler functions
- Unmarshalers.UnmarshalFunc(): Creates type-specific unmarshaler from a function
- Unmarshalers.UnmarshalFromFunc(): Creates type-specific unmarshaler using a decoder
Migration tip
The json/v2
documentation recommends using only v2
going forward (after v2
leaves experimental state), so you might ask how to migrate to v2
without headache. Here's a tip: v2
can mimic specific v1
behavior through legacy options. You can gradually migrate by mixing v1 and v2 options. For example, this code would make the Marshal function behave like v1
but with v2
's case-sensitive matching enabled:
package main
import (
jsonv1 "encoding/json"
jsonv2 "encoding/json/v2"
)
func main() {
v := struct{ a int }{a: 1}
jsonv2.Marshal(v, jsonv1.DefaultOptionsV1(), jsonv2.MatchCaseInsensitiveNames(false))
}
(Run this code with Go 1.25 (RC1 or later) and the environment setting GOEXPERIMENT=jsonv2
)
So rather than turning the JSON-handling parts of your code into a large construction site, you can gradually introduce v2
behavior in manageable iterative steps.
Quote of the Week: wisdom/wisdom.md at master · merlinmann/wisdom
Whenever you catch yourself getting frustrated because you're hung up on some weird implementation detail, please say the following out loud in a firm but friendly tone: "Just do the thing."
More articles, videos, talks
Go Internals: How much can we figure by tracing a syscall in Go?
Ever wondered how Go handles system calls under the hood? Yuvraj Chettri takes you on a journey into Go's unique dual ABI system, custom assembly language, and the rabbit holes of low-level programming.
Understanding Go’s Memory Model: A Visual Guide | by Mojammel Haque Bhuiyan | Jul, 2025 | Stackademic
Usually, diagrams help understanding the text of a blog article. Here, the diagrams are the bulk of the article! Literally a visual guide.
On deep modules
So your newly designed package comes with a rich bouquet of exported types, functions and methods, to provide as much value to the user as possible? Think twice. True power lies in reduction to the essential. You might be able to reduce your package's API to three functions, as Anton Zhiyanov did with his assertion package be
.
Introducing go-cdc-chunkers: chunk and deduplicate everything | Plakar - Effortless backup
Deduplication is easy: Just remove duplcated data. Until you look closer. Deduplication is not that trivial after all, and it's certainly different from (but often confused with) compression. Gilles Chehade lets you look behind the curtains of the go-cdc-chunkers
project, an open source Go package for content-defined chunking.
Parsing Protobuf Like Never Before · mcyoung
The author developed a Protobuf parser for Go that uses a table-driven interpreter approach instead of traditional code generation, to achieve superior performance through runtime optimization and profile-guided optimization. - By Miguel Young de la Sota.
Projects
Libraries
GitHub - sivchari/govalid: Up to 45x faster 🚀 Auto generate type-safe validation code for structs based on markers.
This struct validation library generates code to avoid using slow reflection at runtime. Validation rules are inserted as comment directives.
GitHub - mickamy/go-sql-audit-driver: SQL Audit Driver for Go
A drop-in replacement for database/sql
that adds transparent auditing of DB mutations.
Tools and applications
GitHub - KrishnaSSH/GopherTube: A modern terminal user interface for searching and watching YouTube videos using mpv and chafa
Search for Youtube videos in the terminal with Go & fzf, and watch them in MPV, an open source video player.
GitHub - ft-t/go-money: Go Money is a opensource personal finances manager
Making money with Go is one thing, managing that money a totally different one. Go-Money helps you with this task (although it can't hold you from spending money unwisely).
GitHub - krisfur/gopherdash: Tiny terminal based endless runner game in Go.
A simple side-scrolling game for your next coffee break.
Completely unrelated to Go
Gaslight-driven development
Dark AI forces are taking over! LLMs advise using API functions that don't exist, forcing library developers to add them to their library. What's coming next?

Happy coding! ʕ◔ϖ◔ʔ
Questions or feedback? Drop me a line. I'd love to hear from you.
Best from Munich, Christoph
Not a subscriber yet?
If you read this newsletter issue online, or if someone forwarded the newsletter to you, subscribe for regular updates to get every new issue earlier than the online version, and more reliable than an occasional forwarding.
Find the subscription form at the end of this page.
How I can help
If you're looking for more useful content around Go, here are some ways I can help you become a better Gopher (or a Gopher at all):
On AppliedGo.net, I blog about Go projects, algorithms and data structures in Go, and other fun stuff.
Or visit the AppliedGo.com blog and learn about language specifics, Go updates, and programming-related stuff.
My AppliedGo YouTube channel hosts quick tip and crash course videos that help you get more productive and creative with Go.
Enroll in my Go course for developers that stands out for its intense use of animated graphics for explaining abstract concepts in an intuitive way. Numerous short and concise lectures allow you to schedule your learning flow as you like.
Christoph Berger IT Products and Services
Dachauer Straße 29
Bergkirchen
Germany