jsoniter
A high-performance, 100% compatible drop-in replacement for Go's encoding/json.
Repository Health
Technical Analysis
jsoniter (import path github.com/json-iterator/go, package name jsoniter) is a JSON library for Go that mirrors the standard library’s encoding/json API while decoding and encoding significantly faster. Because Marshal/Unmarshal signatures match the standard library exactly, teams typically adopt it by swapping the import and pointing at one of the library’s preconfigured Config instances — ConfigDefault, ConfigCompatibleWithStandardLibrary, or ConfigFastest — without rewriting struct tags or call sites.
Under the hood it avoids the reflection overhead that makes encoding/json slow: it builds and caches per-type encoder/decoder chains ahead of time using the modern-go/reflect2 package, which reaches into Go’s runtime type layout to read and write struct fields via raw pointers instead of reflect.Value. It also exposes a lower-level Iterator/Stream API for streaming reads and writes, an Any type for lazily-parsed dynamic JSON, and an extension system (RegisterExtension) for customizing field naming, tagging, or per-type codecs.
jsoniter is widely used as an embedded dependency in other Go projects (notably Kubernetes and Istio tooling) specifically to cut JSON marshal/unmarshal latency in hot paths, without giving up standard-library compatibility.
What You Get
- Drop-in API compatibility -
jsoniter.Marshal/Unmarshalmatchencoding/json’s signatures, so most codebases adopt it by changing an import alias. - Three preset configs -
ConfigDefault,ConfigCompatibleWithStandardLibrary(sorted map keys, strict raw-message validation), andConfigFastest(6-digit float precision, no field-name unescaping) for different speed/compatibility trade-offs. - Low-level Iterator/Stream API - streaming token-by-token reads and writes for cases where allocating a full Go value isn’t necessary.
Anytype - a lazily-parsed dynamic JSON value withGet(data, path...)for reaching into nested structures without a full unmarshal.- Extension system -
RegisterExtensionlets callers plug in custom struct-tag handling, field renaming, and per-type encoders/decoders (see theextra/package for naming strategies, fuzzy decoding, and time-as-int64 codecs). RawMessageand standard-library interop - supportsjson.Marshaler/Unmarshalerandencoding.TextMarshaler/TextUnmarshalerso existing custom-marshaling types keep working unmodified.
Common Use Cases
- Hot-path API servers - services that marshal/unmarshal large volumes of JSON per request swap in jsoniter to cut CPU time without touching handler code.
- Kubernetes-adjacent tooling - projects in the Kubernetes/Istio ecosystem embed jsoniter internally to speed up serialization of API objects.
- Streaming JSON processing - pipelines that need to read or write JSON incrementally (rather than loading a whole document into memory) use the
Iterator/StreamAPI directly. - Partial/lazy JSON access - code that only needs a few fields out of a large JSON payload uses
Any/Getto avoid a full struct unmarshal. - Custom field-naming conventions - teams needing non-standard-library struct-tag behavior (fuzzy decoding, alternate naming strategies) use the extension system rather than forking
encoding/json.
Under The Hood
Architecture
The package is a flat, single-namespace Go module (package jsoniter) rather than a layered directory tree: adapter.go exposes the standard-library-shaped surface (Marshal, Unmarshal, NewEncoder, NewDecoder), config.go defines the Config/frozenConfig type that holds per-configuration behavior flags (SortMapKeys, EscapeHTML, CaseSensitive, etc.) plus cache maps keyed by reflect2.RType, and reflect.go/reflect_extension.go/reflect_struct_decoder.go do the actual work of building a ValEncoder/ValDecoder tree for a given Go type on first use and caching it for every subsequent call. Reading and writing happen through Iterator (iter.go, iter_object.go, iter_array.go, etc.) and Stream (stream.go), both of which operate on raw byte buffers rather than reflect.Value, keeping the hot path allocation-free for simple structs. If the core ctx/cache-key abstraction in reflect.go changed, every encoder/decoder implementation across the codebase would need to change with it — the caching contract is the load-bearing abstraction the rest of the package is built around.
Tech Stack
Written in Go (module github.com/json-iterator/go, go 1.12 in go.mod) with a deliberately small runtime dependency set: github.com/modern-go/reflect2 (unsafe-pointer-based reflection used to bypass reflect.Value allocation), github.com/modern-go/concurrent (the map-like cache used for encoder/decoder lookup), plus github.com/stretchr/testify, github.com/davecgh/go-spew, and github.com/google/gofuzz as test-only dependencies. There is no external build tooling beyond go build/go test; a build.sh/test.sh pair and a .travis.yml config exist for CI, though the CI config targets an old Go toolchain (1.8.x/1.x) and hasn’t been updated to reflect current Go versions.
Code Quality
The repository has an extensive test suite — roughly 48 files containing Test-prefixed functions across type_tests/, any_tests/, api_tests/, misc_tests/, skip_tests/, value_tests/, and extension_tests/ directories, using testify for assertions and table-driven testCases slices that exercise a large matrix of Go types (arrays, pointers, nested structs, aliases). Error handling in the public API follows the encoding/json convention of returned/reported errors rather than panics (iter.ReportError), and comment density on core files is moderate — exported types and non-obvious cache/pointer logic are documented, but the reflection-heavy internals (reflect_struct_decoder.go, reflect_extension.go) rely on the reader already understanding Go’s unsafe/reflect2 model. There’s no dedicated linter config or docs/ directory, and the CI pipeline (Travis) is stale relative to the project’s last commit.
What Makes It Unique
The library’s core trick is API-compatible drop-in replacement combined with ahead-of-time cached, unsafe-pointer-based encoding/decoding: rather than exposing a different API and asking callers to opt in explicitly (as most “faster JSON” libraries do), it reproduces encoding/json’s exact function signatures and behavior toggles (via ConfigCompatibleWithStandardLibrary) so adoption is a near-zero-diff import swap. Building on reflect2 instead of the standard reflect package to read/write struct fields directly through pointers, and caching the resulting encoder/decoder graph per concrete type, is the specific technical choice that produces its speed advantage over encoding/json without requiring compile-time code generation the way easyjson-style libraries do.
Used by 14 apps in this directory
PeerDB
Data Engineering · Databases
Postgres-native ETL that streams change data capture in real time to Snowflake, BigQuery, ClickHouse, S3, and Kafka — up to 10x faster than general-purpose pipelines, managed through a familiar Postgres SQL interface.
SigNoz
Analytics · Monitoring
Self-host your entire observability stack — logs, metrics, traces, and LLM monitoring — in one OpenTelemetry-native platform, without the Datadog bill.
Teleport
Authentication · Security
Zero-trust infrastructure access platform that replaces credentials and VPNs with short-lived certificates, SSO, and identity-aware proxies for SSH, Kubernetes, databases, RDP, and AI agents.
Tianji
Analytics · Monitoring
Replace Google Analytics, UptimeKuma, and Prometheus with one self-hosted platform that tracks websites, monitors uptime, and reports server health.
TiDB
AI Development · Databases
AI-Native Distributed SQL Database for Agentic Workloads