Library / SDK
bytedance/sonic-cpp avatar
bytedance/sonic-cpp

sonic-cpp trades portability for SIMD speed on x86 Linux

A fast JSON serializing & deserializing library, accelerated by SIMD.

980 stars128 forksC++Apache-2.0

At a glance

What is it?
sonic-cpp is a header-only C++ JSON library that parses into a compact document tree and leans on AVX2 for whitespace skipping, escape detection and on demand parsing. The requirements list is the honest summary of what it is: C++11, x86 with AVX2, GCC or LLVM, and Linux, which makes it a fast choice for a specific platform and an awkward one everywhere else.
Who is it for?
sonic-cpp is a good fit for a service on x86 Linux that parses or writes a lot of JSON and has a measured bottleneck in its JSON path, and it is a good fit for a C++ codebase that already targets AVX2 and wants a header-only dependency with no build step.
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 13 days ago.
What is it written in?
Mainly C++, according to GitHub's language statistics.

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

Editorial analysis

The requirements list is the real product description

Sonic-Cpp states its requirements in four lines and they narrow the audience more than any feature list would. It needs C++11 or above, an x86 platform with AVX2 instruction, a GCC or LLVM compiler, and it explicitly does not support the MSVC compiler. The operating system requirement is Linux. Nothing in the documentation promises a fallback path, and the roadmap rather confirms it, since support for more platforms such as ARM is still an open item. The library is described as a fast JSON serialising and deserialising library accelerated by SIMD, with complete APIs for JSON value manipulation, fast serialising and parsing, and support for parse on demand. It is published under the Apache License 2.0, and the repository carries a `licenses/` directory alongside the LICENSE file.

Header-only means the build system barely matters

The usage section states that Sonic-Cpp is a header-only library and that you only need the include directory of the Sonic-Cpp header files, such as adding `-I/path/to/sonic/include/` to your compiler. There is nothing to link and nothing to install, which removes the usual friction when adding a C++ dependency to a service, and it explains why the repository ships both a CMakeLists.txt and a Bazel setup with a BUILD.bazel file and a .bazelversion. The cost of that choice is that everything is compiled into every translation unit that includes it, so compile time and binary size are yours to manage rather than the library's. The example programs in the repository show the convention for a compiler invocation, and they use a specific instruction set target rather than a generic one:

bash
g++ -I./include/ -march=haswell --std=c++11 -O3 example/parse_and_serialize.cpp -o example/parse_and_serialize

The `-march=haswell` flag is what makes the AVX2 code paths available, and it is the one line of the build that ties the library to the platform requirement in the previous section.

The document tree is compact and the SIMD work is in the scanning

Sonic-cpp parses JSON into a compact document tree, and the design notes explain where the speed comes from rather than asserting it. Whitespace skipping is accelerated with SIMD. Escaped characters inside strings are found with SIMD as well. Numbers are converted with the STOA float parsing algorithm. On the write side the same idea is applied in reverse: when serialising a string, the escaped characters are checked first, and SIMD instructions from the AVX2 and SSE sets are used to locate them in a long JSON string. The shape of the design is worth understanding because it explains the shape of the API. A document model with a `Document` type, a `Node` type, member iterators and typed accessors is a fairly conventional tree, and the speed does not come from a novel data structure but from doing the scanning work several bytes at a time instead of one character at a time.

ParseOnDemand is for when you already know the key

The on-demand parsing mode is the one with the clearest use case. ParseOnDemand is available when the user knows the target key at compile time, and the documentation notes that it also uses SIMD, together with bit manipulation, to skip unwanted values quickly. In a service that reads a fixed envelope, for example a message with an identifier and a payload field, this avoids building a full tree for data the program will never look at, and the skipping is done at the instruction level rather than by walking and discarding nodes. The repository has a dedicated example file for it, and the examples list also covers pointer access, schema based parsing, adding members, creating and destroying maps, and checking the error offset, which is the detail you want when a payload fails to parse and you have to report where.

The accessor API is explicit and typed

The value model is exposed through a family of methods that the documentation lists in full: `IsNull` and `SetNull`, `IsBool`, `GetBool` and `SetBool`, `IsString`, `GetString`, `GetStringView` and `SetString`, `IsNumber`, `IsArray` and `SetArray`, `IsObject` and `SetObject`, `IsTrue` and `IsFalse`, `IsDouble`, `GetDouble` and `SetDouble`, `IsInt64`, `GetInt64` and `SetInt64`, and `IsUint64`, `GetUint64` and `SetUint64_t`. The pattern of a type check followed by a getter is deliberate: a program is expected to test before it reads, which keeps the accessors cheap and the failure modes explicit. Errors are handled through the same object, since a document carries a parse error state that a caller can query after parsing. The example programs show the intended flow: parse into a `Document`, check for a parse error, then work with members found by key.

Reproducing the benchmark and the API documentation

The repository lets you run its own benchmark, and the instructions are given for two build systems. With CMake the sequence is:

bash
cmake -S . -B build -DBUILD_BENCH=ON
cmake --build build --target bench -j
./build/benchmark/bench

With Bazel the equivalent is a single command:

bash
bazel run :benchmark --compilation_mode=opt

The results in the README are shown as images, the parsing and serialising comparison charts, plus a set of numbers attributed to a third party benchmark project, which is the more useful of the two comparisons because it runs your build against other implementations on the same machine. API documentation is generated with Doxygen, and the documented steps are:

shell
mdkir api-doc && cd api-doc
doxygen ../Doxyfile

Doxygen 1.8.13 or higher is required. The benchmark directory, the `fuzz/` directory and the `tests/` directory with a `testdata/` folder are all in the tree, so the library is tested against stored corpora and fuzzed, and the CI badges in the README point at a clang-format check and an x86 test workflow.

The roadmap is the honest limit list

The README ends with a roadmap in which every box is still empty, and the list is more informative than the feature section. Support for `RawNumber` in JSON parsing is open. JSON Path, JSON Merge Patch under RFC 7396 and JSON Pointer under RFC 6901 are all open, which means the library does not yet cover the pointer and patch vocabulary a lot of JSON tooling assumes. Support for more platforms such as ARM is open. Struct binding is open, so the library has no automatic mapping between C++ structs and JSON the way some competitors offer. Validating UTF-8 is open, which is a real gap for a library whose parser is otherwise strict, since malformed input is only reported as a parse error rather than validated for encoding. On releases, the last three are v1.0.0 from 2023-02-06, v1.0.1 from 2024-05-24 and v1.0.2 from 2025-03-07, while the last push to the repository was on 2026-10-10, so the code is still being worked on while the published version numbers have not moved in a while.

Editorial conclusion

sonic-cpp is a good fit for a service on x86 Linux that parses or writes a lot of JSON and has a measured bottleneck in its JSON path, and it is a good fit for a C++ codebase that already targets AVX2 and wants a header-only dependency with no build step. It is a poor fit for a portable codebase, for Windows, for Apple silicon, or for a project that needs JSON Pointer, JSON Path, JSON Merge Patch, struct binding or UTF-8 validation, since each of those is still an unchecked box on the roadmap. Before you adopt it, check three things: that your compilers are GCC or LLVM and your target enables AVX2, that the version you vendor matches the release line you intend to support, with the latest release at v1.0.2 from 2025-03-07 and the last push on 2026-10-10, and that the licence file in the repository covers your use, since the project is published under Apache-2.0.

Frequently asked questions

What are the requirements for sonic-cpp?

C++11 or above, an x86 platform with AVX2, a GCC or LLVM compiler and Linux. The documentation states that the MSVC compiler is not supported, and support for more platforms such as ARM is still an open item on the roadmap.

How do I add sonic-cpp to a C++ project?

It is header-only, so you add the include directory to your compiler flags, for example `-I/path/to/sonic/include/`, and include the header. The example programs compile with a march flag such as `-march=haswell` to enable the AVX2 code paths.

What is ParseOnDemand in sonic-cpp and when should I use it?

It is a parsing mode for the case where you know the target key at compile time. It uses SIMD and bit manipulation to skip unwanted values quickly instead of building a full document tree for data the program will not read.

How do I build the sonic-cpp benchmark?

With CMake, run `cmake -S . -B build -DBUILD_BENCH=ON`, then `cmake --build build --target bench -j`, then `./build/benchmark/bench`. With Bazel the single command is `bazel run :benchmark --compilation_mode=opt`.

Does sonic-cpp support JSON Pointer or JSON Path?

Not yet. JSON Path, JSON Merge Patch under RFC 7396 and JSON Pointer under RFC 6901 are all unchecked items on the project roadmap, as are struct binding and UTF-8 validation.

Official sources

  1. bytedance/sonic-cpp 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-cpp.svg)](https://hysenlabs.com/projects/bytedance-sonic-cpp)

Was this useful?