JSON Encoding
encoding/json โ No Third Party Needed
Go's standard library includes a complete JSON implementation in the encoding/json package. You do not need any external dependency to marshal structs to JSON or unmarshal JSON into Go types.
Struct Tags
Struct tags are string literals in backticks that annotate fields with metadata. The encoding/json package reads the json key to control serialization:
The tag maps the exported Go field name to the lowercase JSON key. Without a tag, Go uses the field name as-is, so Name would appear as "Name" in JSON.
omitempty โ omits the field when its value is the zero value for its type (empty string, 0, false, nil):
"-" โ always excludes the field from JSON, even if it has a value:
Marshaling: Go โ JSON
json.Marshal converts a Go value to a JSON byte slice:
For human-readable output, use json.MarshalIndent:
Unexported fields are silently omitted โ json.Marshal can only see exported (capitalized) fields.
Unmarshaling: JSON โ Go
json.Unmarshal parses a JSON byte slice into a Go value. Pass a pointer so the function can populate the struct:
Unknown JSON fields are silently ignored by default โ the "extra" key in the JSON will not cause an error.
Nested Structs and Slices
Struct fields can themselves be structs or slices โ the JSON encoder handles nesting automatically:
Embedded Structs
When a struct is embedded (without a field name), its fields are promoted to the top-level JSON object:
Marshaling an Article produces {"created_at":...,"updated_at":...,"title":...} โ the Timestamps fields appear at the top level.
Streaming I/O with Encoder and Decoder
When reading from or writing to a network connection or file, avoid buffering the entire JSON in memory. Use json.NewEncoder and json.NewDecoder instead:
json.NewEncoder(w).Encode(v) is idiomatic in HTTP handlers that write JSON responses to http.ResponseWriter.
Dynamic JSON with map[string]any
When the JSON structure is unknown at compile time, unmarshal into map[string]any:
JSON numbers decode as float64 by default. Use json.Decoder with UseNumber() if you need to distinguish integers from floats.
Knowledge Check
What struct tag makes a JSON field optional (omitted when zero value)?
What happens to unexported struct fields during json.Marshal?
Which function is best for streaming JSON to an io.Writer?