Library / SDK
bytedance/sonic avatar
bytedance/sonic

bytedance/sonic: a JIT and SIMD JSON codec for Go

A blazingly fast JSON serializing & deserializing library

9,657 stars486 forksGoApache-2.0

At a glance

What is it?
Sonic replaces encoding/json with a runtime-compiled codec that binds Go structs without code generation. It is fast on AMD64 and ARM64, but it carries real platform and toolchain constraints.
Who is it for?
Adopt Sonic when you are on Linux, macOS or Windows with an AMD64 or ARM64 CPU, you can pin your Go toolchain, and JSON encode/decode time shows up in a profile. Do not adopt it if you need a broad architecture matrix, if you cannot move off Go 1.24.0, or if your JSON volume is small enough that encoding/json is not a measurable cost.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 18 days ago.
What is it written in?
Mainly Go, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on November 14, 2026, and from our analysis. They are not legal advice.

From daily snapshots

Star history

  • bytedance/sonic9,657 ★ · +56
Star history
Repository2026-09-222026-11-14
bytedance/sonic9.6k9.7k

56 Stars in the last 53 days, measured from the daily GitHub snapshot. Compare with other projects

Editorial analysis

What Sonic replaces and who it is for

Sonic is a JSON serializing and deserializing library for Go, published by ByteDance under Apache-2.0. It targets the same job as encoding/json: turning structs into bytes and bytes back into structs. The difference is the implementation strategy. The README describes it as accelerated by JIT (just-in-time compiling) and SIMD (single-instruction-multiple-data), and lists three features: runtime object binding without code generation, complete APIs for JSON value manipulation, and speed.

The audience is narrow but real. If you run a Go service that spends a visible share of CPU inside JSON, and you are on AMD64 or on ARM64 with Go 1.20 or above, Sonic is aimed at you. If your service is I/O bound and JSON never appears in a profile, the added platform constraints buy you nothing. The README's own benchmark table compares Sonic against json-iterator/go and a GoJson variant in its visible output, which tells you the intended comparison set is the common third-party codecs, not a new abstraction.

How the JIT and SIMD path actually works

The mechanism is a codec that compiles its own decoders and encoders at runtime rather than generating Go source ahead of time. That is what the README means by "runtime object binding without code generation": there is no go:generate step and no generated file to commit. The binding happens when the program runs.

The repository layout confirms the split. There is a decoder/ directory, an encoder/ directory, an ast/ package for JSON value manipulation, an internal/ tree, a native/ directory, a loader/ module, and a separate go.mod dependency on github.com/bytedance/sonic/loader v0.5.3. The loader is versioned independently, with its own release tag loader/v0.5.3. There is also an unquote/ package and a utf8/ package, which is what you would expect from a codec that wants to avoid calling into the standard library for string and encoding work.

The dependency list is a good signal of how the speed is obtained. go.mod pulls github.com/klauspost/cpuid/v2 for CPU feature detection, github.com/cloudwego/base64x for base64 work, github.com/twitchyliquid64/golang-asm and golang.org/x/arch for assembly generation, and github.com/bytedance/gopkg. This is not a pure-Go rewrite of encoding/json. It inspects the CPU and emits architecture-specific code paths at runtime.

Getting Sonic into a Go module

The module path is fixed by go.mod: module github.com/bytedance/sonic, and a pointer to the API reference with "see go.dev". The README says Sonic's default behaviors are mostly consistent with encoding/json, except HTML escaping and the SortKeys feature, and its usage examples call sonic.Marshal and sonic.Unmarshal.

What the README does document is the requirement block, and that is where an install decision actually gets made. Before fetching anything, check the Go version and the CPU. The README lists Go 1.18 through 1.27, with Go 1.24.0 excluded, and it lists Linux, macOS and Windows on AMD64, or ARM64 with Go 1.20 above. The README gives one workaround for the 1.24.0 gap, a build flag:

code
-ldflags="-checklinkname=0"

If your toolchain sits at 1.24.0 and you cannot thread that flag through every compile step, stop here rather than fetching the module.

For a first real use, the README points at pkg.go.dev for the API surface and the repository carries examples/example_stream_test.go for a streaming case. The README also has a Streaming IO section showing sonic.ConfigDefault.NewEncoder and NewDecoder over an io.Writer and an io.Reader. Plan the swap as something you validate against your own test suite rather than something the project walks you through.

The Go 1.24.0 gap and the architecture matrix

The most concrete limitation is stated plainly in the README's Requirement section. Sonic supports Go 1.18 through 1.27, with one exclusion: Go 1.24.0 is not supported, because of an issue tracked at golang/go#71672. The README offers two ways out, either use a higher Go version or pass the build flag -ldflags="-checklinkname=0".

That is a sharper constraint than it first appears. A toolchain patch release is normally something a team takes without a second thought. Here, moving to 1.24.0 breaks the library unless you also change your link flags, and a link flag is a build-system change that has to be threaded through every place you compile. If your organisation pins Go versions centrally and 1.24.0 is in the approved set, Sonic is the wrong choice until that pin moves.

The second constraint is the CPU and OS matrix. The README lists Linux, macOS and Windows, and AMD64 or ARM64, with ARM64 requiring Go 1.20 or above. Because the speed comes from JIT and SIMD, the matrix is narrow. If you ship to an architecture outside that list, encoding/json remains the portable answer.

What the benchmark table does and does not tell you

The README's benchmark section opens with a strong claim: for all sizes of JSON and all scenarios of usage, Sonic performs best. The table behind that claim is a single machine, and the README says so: goos darwin, goarch amd64, an Intel Core i9-9880H at 2.30 GHz, Go 1.17.1, on a 13KB payload with 300+ keys and 6 layers.

That is a useful disclosure because it bounds the claim. The numbers are from one CPU, one OS and one Go version, on a medium-sized document. The README also defines Small (400B) and Large (635KB) test inputs, but the visible numbers are for the medium document, so reproduce the small and large cases with the repository's scripts/bench.sh before relying on the headline claim.

The comparison set is equally specific. The visible benchmark output compares Sonic against json-iterator/go and a GoJson variant. Those are the alternatives the project chose to measure against, and scripts/bench.sh is the place to reproduce them locally.

json-iterator/go and gjson as the practical alternatives

json-iterator/go is the closest drop-in alternative. It also presents an encoding/json-compatible surface, but it does not compile decoders at runtime and does not depend on assembly generation. That means it works on a wider set of architectures without a CPU feature check, at the cost of the throughput shown in Sonic's table. If your deployment includes an architecture outside AMD64 and ARM64, json-iterator/go is the safer default and the benchmark difference is the price of portability.

gjson solves a different problem. It is a read-only path for pulling single values out of a JSON document. If all you do is extract a field or two from a large payload, gjson avoids building a Go value at all. Sonic's ast/ package covers similar ground inside the same library, so the choice between them is whether you want one dependency for both full binding and path reads, or a smaller dependency for reads only.

There is also the option the README does not push: staying on encoding/json. It is in the standard library, it has no architecture list, and it has no toolchain exclusions. Sonic is a replacement for it, not a complement.

Maintenance, licensing and the cost of the loader split

The repository is not archived, and the last push was on 2026-10-27. Releases are frequent: v1.15.5 on 2026-10-27, loader/v0.5.3 on 2026-10-21, and v1.15.4 on 2026-09-11. The loader is tagged on its own cadence, separate from the main module. That split is worth understanding before you adopt. Your go.mod will pin github.com/bytedance/sonic/loader independently of github.com/bytedance/sonic, so an upgrade can move one without the other. The go.mod also carries a commented-out replace directive for the loader, which is the mechanism the maintainers use to develop against a local copy.

Licensing is Apache-2.0 for the main module, and the repository root contains a LICENSE file, a licenses/ directory and a .licenserc.yaml, which suggests third-party licence tracking is part of the build. Apache-2.0 is permissive and includes an explicit patent grant, but it also carries notice and attribution obligations, so redistributing a binary built with Sonic is not the same as redistributing one built only on the standard library. That is a compliance question for your own legal review, not something this article can settle.

The upgrade cost is the toolchain coupling. Every Go release in the supported window needs to be checked against the library, and the Go 1.24.0 exclusion shows that this check is not theoretical. Budget for a Go version bump to be a two-part change: the toolchain and the codec.

Editorial conclusion

Adopt Sonic when you are on Linux, macOS or Windows with an AMD64 or ARM64 CPU, you can pin your Go toolchain, and JSON encode/decode time shows up in a profile. Do not adopt it if you need a broad architecture matrix, if you cannot move off Go 1.24.0, or if your JSON volume is small enough that encoding/json is not a measurable cost. Before switching, verify three things on your own build: that your Go version is outside the 1.24.0 gap, that your target GOARCH is AMD64 or ARM64 with Go 1.20 or above on ARM64, and that your own test suite passes with Sonic in place.

Frequently asked questions

Does bytedance/sonic work on ARM64?

Yes, the README lists ARM64 as supported, with the additional requirement that the Go version be 1.20 or above. AMD64 has no such extra requirement.

Which Go versions does bytedance/sonic support?

The README states Go 1.18 through 1.27, with Go 1.24.0 excluded because of a reported issue. For 1.24.0 the README suggests either a higher Go version or the build flag -ldflags="-checklinkname=0".

Does bytedance/sonic need code generation?

No. The README lists runtime object binding without code generation as a feature, so binding happens while the program runs rather than through generated Go source.

Official sources

  1. bytedance/sonic on GitHub
  2. Issues
  3. License: Apache-2.0
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/bytedance-sonic.svg)](https://hysenlabs.com/projects/bytedance-sonic)

Star history chart for your README

markdown
[![Star history](https://hysenlabs.com/chart/bytedance-sonic.svg)](https://hysenlabs.com/projects/bytedance-sonic)

Was this useful?