Open-source project
mailru/easyjson avatar
mailru/easyjson

easyjson generates Go JSON code without reflection for faster marshaling

Fast JSON serializer for golang.

4,916 stars469 forksGoMIT

At a glance

What is it?
easyjson is a Go library that writes marshaler and unmarshaler code for your structs so JSON encoding and decoding skip reflection and run faster than the standard encoding/json package.
Who is it for?
easyjson is a Go code generation library that replaces runtime reflection with a build time step, producing marshalers and unmarshalers that the README says run 4 to 5 times faster than encoding/json. It installs with the Go toolchain, generates a companion file through the easyjson -all command, and exposes options for naming, omitting fields, and rejecting unknown keys.
Can I use it commercially?
Yes. MIT 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?
Activity is slowing. The repository last received commits 6 months 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 October 1, 2026, and from our analysis. They are not legal advice.

Editorial analysis

easyjson avoids reflection for Go JSON work

easyjson is a Go package that turns struct definitions into dedicated marshaler and unmarshaler functions. The standard library encoding/json uses reflection at runtime to discover the fields of every struct it touches, which costs CPU time on each call. easyjson moves that work to a build step: a code generator reads your Go source file and writes a companion file with the same types plus hand-written encode and decode routines. The README states that in performance tests easyjson outperforms the standard encoding/json package by a factor of 4 to 5 times, and other JSON encoding packages by 2 to 3 times. The project also aims to keep the generated Go code simple enough that a developer can read it, optimize it, or patch it by hand. That balance of speed and readability is the main reason teams reach for a generator instead of the built-in package when JSON sits on a hot path.

Installing and running the generator

easyjson is installed through the Go toolchain, and the README shows separate commands based on the Go version in use. Once the binary is on your path you point it at a source file and it emits a new file alongside the original. Running the tool with the -all flag produces a file named <file>_easyjson.go that holds the appropriate marshaler and unmarshaler functions for all structs contained in the input. The README notes that easyjson requires a full Go build environment and the GOPATH variable to be set, because the code generation step invokes go run on a temporary file. That technique was borrowed from the ffjson project. With the generator in place, encoding and decoding your types becomes a matter of calling the generated functions rather than paying for reflection every time.

sh
# for Go >= 1.17
go get github.com/mailru/easyjson && go install github.com/mailru/easyjson/...@latest
sh
easyjson -all <file>.go

Calling the generated marshalers

After the companion file exists, your program marshals a struct by calling easyjson.Marshal, which returns raw bytes and an error. To read JSON back, you call easyjson.Unmarshal with a pointer to a target struct. The generated file also defines MarshalEasyJSON and UnmarshalEasyJSON, which satisfy the easyjson.Marshaler and easyjson.Unmarshaler interfaces, and when used with the package level Marshal and Unmarshal calls they avoid extra reflection and type assertions. The README warns that using the standard json.Marshal and json.Unmarshal on these structs brings a significant performance penalty compared with the easyjson functions. The package also ships utility functions built on those lower level routines, such as one that marshals a value straight to a standard http.ResponseWriter, which is useful when streaming JSON from a web handler.

go
someStruct := &SomeStruct{Field1: "val1", Field2: "val2"}
rawBytes, err := easyjson.Marshal(someStruct)
go
someStruct := &SomeStruct{}
err := easyjson.Unmarshal(rawBytes, someStruct)

Command line options for code generation

The generator accepts flags that shape the output it writes. Passing -all generates code for every struct in the file, while leaving it off means only the structs whose preceding comment starts with easyjson:json get code. A preceding comment that starts with easyjson:skip excludes a struct from generation entirely. Other flags let you tune the result: -snake_case emits snake_case field names by default, -lower_camel_case switches to lowerCamelCase, -omit_empty drops empty fields by default, and -disallow_unknown_fields returns an error when the JSON contains a key the struct does not recognize. The -stubs flag writes only the function shells, while -build_tags and -gen_build_flags pass extra flags through to the build that bootstraps the generator. Together these options cover most naming and validation conventions without editing the generated source.

Customizing behavior with tags and interfaces

Beyond the standard omitempty tag, easyjson understands a few extra options attached to json struct tags. The nocopy option disables allocation and copying of string values so they refer directly to the original JSON buffer memory, which helps short lived objects that are consumed and discarded right after decoding. The intern option turns on string interning, deduplicating repeated string values in memory, which saves RAM when the same dictionary strings appear throughout a structure. A Go type can also supply its own MarshalEasyJSON and UnmarshalEasyJSON functions that satisfy the easyjson interfaces, and those will be used by the package level calls. Types may further implement the easyjson.Optional interface to define their own omitempty logic, giving precise control over when a field is written out.

Performance, pooling, and safety notes

easyjson keeps a buffer pool that allocates data in increasing chunks from 128 up to 32768 bytes, and chunks of 512 bytes and larger are reused with the help of sync.Pool. The README lists several behavior limits worth knowing. Object keys are case sensitive, so unlike the standard library there is no case-insensitive matching. There is currently no true streaming support for encoding or decoding. High precision floats are formatted with Go's default strconv precision, which can be insufficient for exact values. The parser uses unsafe to convert bytes to strings without copying, which the README says delivers a real speed gain; you can compile without it by setting the easyjson_nounsafe build tag. On Google App Engine the platform build tag disables unsafe automatically, because it is not allowed in that environment, and the README marks that combination as still experimental.

Type wrappers and memory optimizations

The easyjson/opt package defines type wrappers around the standard Go primitives, and those wrappers satisfy the easyjson interfaces. They are useful when you must distinguish a missing value from a zero value, or when you want to specify a default. Because the wrappers avoid extra pointers and heap allocations, they can raise performance noticeably when applied in the right places. String interning is a related lever: adding the intern tag to a string field deduplicates its value during unmarshaling, trading a small amount of CPU for lower memory use when that field repeats the same small set of values. The README frames these as opt-in controls, so the default behavior stays simple and the advanced memory tricks are available only where a profile shows they help.

Editorial conclusion

easyjson is a Go code generation library that replaces runtime reflection with a build time step, producing marshalers and unmarshalers that the README says run 4 to 5 times faster than encoding/json. It installs with the Go toolchain, generates a companion file through the easyjson -all command, and exposes options for naming, omitting fields, and rejecting unknown keys. Extra touches such as the opt package wrappers, string interning, a reusable buffer pool, and a no-unsafe build tag give developers direct control over speed and memory. For Go services that encode and decode JSON on hot paths, easyjson offers a straightforward way to cut that cost without hand-writing the boilerplate.

Frequently asked questions

Is JSON secure?

JSON is a text format for exchanging data, not an executable program, so safety depends on how the data is parsed rather than on JSON itself. easyjson generates code without reflection and uses unsafe only for a no-copy conversion, with a build tag to disable that behavior, but any parser of untrusted input still needs normal validation and limits.

Does easyjson use reflection for marshaling?

No. The README states easyjson marshals and unmarshals Go structs without the use of reflection by generating dedicated code at build time. Using the standard library json.Marshal or json.Unmarshal on those structs instead incurs a significant performance penalty.

How do I generate code for all structs in a file?

Run the generator with the -all flag against a Go source file, for example easyjson -all <file>.go. This writes a companion <file>_easyjson.go containing the marshaler and unmarshaler functions for every struct in that file.

Official sources

  1. Issues
  2. License: MIT
  3. mailru/easyjson on GitHub
  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/mailru-easyjson.svg)](https://hysenlabs.com/projects/mailru-easyjson)