easyjson

Reflection-free JSON marshaling and unmarshaling for Go, generating type-specific code up to 5x faster than encoding/json.

Library
Go
vv0.9.2
4,916stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
49/100Fair
Development Activity4
Maintenance20
Community72
Maturity60
Momentum40

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
66/100Good
Architecture78
Code Quality80
Innovation72
Learning Curve35

easyjson is a Go code generator and runtime library that produces reflection-free JSON marshalers and unmarshalers for your structs. Instead of relying on encoding/json’s runtime reflection, it parses your Go source, generates MarshalEasyJSON/UnmarshalEasyJSON methods per struct, and pairs them with a lightweight jwriter/jlexer runtime, delivering roughly 4-5x faster unmarshaling and 3-4x faster marshaling than the standard library with far fewer allocations.

Generated types remain compatible with encoding/json via standard MarshalJSON/UnmarshalJSON methods, so adoption is incremental: run the easyjson CLI over annotated files and only the touched structs get accelerated. Options for snake_case naming, omitempty defaults, string interning, and strict unknown-field rejection make it a practical drop-in for high-throughput services that serialize a lot of JSON.

What You Get

  • easyjson CLI - a go-generate-friendly code generator that scans annotated (//easyjson:json) or all structs in a file or package and emits _easyjson.go marshaler/unmarshaler methods.
  • jlexer/jwriter runtime - a minimal, allocation-conscious JSON lexer and writer that generated code calls into instead of encoding/json’s reflection path.
  • encoding/json compatibility - generated types also satisfy json.Marshaler/json.Unmarshaler, so they interoperate with existing encoding/json-based code with no changes.
  • Buffer pooling - a sync.Pool-backed buffer package that reuses chunks between marshal calls to cut allocations under load.
  • String interning and nocopy tags - opt-in struct tag options for deduplicating repeated string values and avoiding string copies during unmarshaling.

Common Use Cases

  • High-throughput HTTP APIs - services that marshal and unmarshal large volumes of JSON request/response bodies use easyjson to cut CPU time and GC pressure versus encoding/json.
  • Hot-path logging and telemetry pipelines - systems serializing structured events at high frequency generate easyjson methods for the event types to reduce marshaling overhead.
  • Large or nested payload processing - workloads dealing with big JSON documents, such as search or analytics data, benefit from easyjson’s lower allocation profile on large structs.
  • Gradual migration off encoding/json - teams add easyjson incrementally to specific hot structs while leaving the rest of the codebase on the standard library, since generated types stay drop-in compatible.

Under The Hood

Architecture The module cleanly separates generation-time code from runtime code: parser walks Go source with reflect-friendly AST tooling to find annotated structs, gen emits the encoder/decoder Go source for each type, and bootstrap orchestrates the temporary-file go run invocation that the easyjson CLI (in easyjson/main.go) drives. None of that machinery is imported by generated code at runtime; instead, generated methods call into the root easyjson package (helpers.go, raw.go, unknown_fields.go) plus the standalone jlexer, jwriter, buffer, and opt packages, so there is no import cycle between codegen and runtime concerns, and the runtime footprint stays small.

Tech Stack The module targets Go 1.20 and has a single external dependency, github.com/josharian/intern, for its string-interning option. The CLI is a plain flag-based command with no third-party CLI framework, code generation is driven by a Makefile invoking go generate and go test across the bootstrap package, and CI runs the full suite on Go 1.23 via GitHub Actions. Performance-critical paths use the unsafe package for zero-copy byte-to-string conversion, guarded by an easyjson_nounsafe build tag for environments like Google App Engine that disallow it.

Code Quality The repository carries 22 test files spanning jlexer, buffer, gen, parser, and a dedicated tests/ package that generates easyjson code for purpose-built structs and round-trips them, covering escaping, string interning, nocopy semantics, unknown-field handling, HTML-safe escaping, and required fields. Errors are propagated explicitly through Writer.Error and Lexer.Error() fields rather than panics or silent drops, naming is consistent and idiomatic Go throughout, and GitHub Actions CI builds and tests on every push and pull request; there is no modern linter configuration checked in, only a legacy golint install step in CI.

What Makes It Unique Rather than reimplementing JSON parsing under a new abstraction, easyjson generates types that still satisfy the standard json.Marshaler/json.Unmarshaler interfaces, so adoption is incremental and non-invasive against existing encoding/json-based code. Its combination of struct-tag-driven behavior (nocopy, intern), a pooled buffer allocator, and an escape hatch from unsafe conversions gives it a level of tunability that most reflection-avoidance JSON generators for Go don’t expose, though it does require a full Go toolchain and GOPATH-aware environment to run its generator, since generation itself invokes go run on a temporary file.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search