encoding/json
JSON in Go
Section titled “JSON in Go”The encoding/json package converts Go values to JSON text (marshaling) and JSON text back to Go values (unmarshaling). The two central functions are:
data, err := json.Marshal(v) // Go value → []byte (JSON)err = json.Unmarshal(data, &v) // []byte (JSON) → Go valueMarshal takes any value and returns a []byte. Unmarshal writes into the value pointed to by the second argument — always pass a pointer so the function can modify the variable.
Struct tags
Section titled “Struct tags”A struct tag is a raw-string literal on a struct field that provides metadata. The encoding/json package reads json:"name" tags to control serialization:
type User struct { Name string `json:"name"` Email string `json:"email,omitempty"` Age int `json:"age"`}The tag syntax is `json:"<name>[,options]"`. Common options:
| Tag | Effect |
|---|---|
json:"name" | Use name as the JSON key instead of the field name |
json:"name,omitempty" | Omit this field from the output when its value is the zero value |
json:"-" | Always omit this field |
Nested structs
Section titled “Nested structs”Struct fields can themselves be structs. json.Marshal recurses into them automatically:
type Address struct { City string `json:"city"` Country string `json:"country"`}
type User struct { Name string `json:"name"` Age int `json:"age"` Address Address `json:"address"`}The resulting JSON nests the address object under the "address" key.
map[string]any — flexible unmarshaling
Section titled “map[string]any — flexible unmarshaling”When you do not have a struct type ahead of time, unmarshal into map[string]any. Each JSON value becomes its natural Go counterpart: string, float64, bool, []any, map[string]any, or nil.
var m map[string]anyjson.Unmarshal([]byte(`{"lang":"Go","version":1.22}`), &m)fmt.Println(m["lang"]) // Gofmt.Println(m["version"]) // 1.22 (float64)package main
import ( "encoding/json" "fmt")
type Address struct { City string `json:"city"` Country string `json:"country"`}
type User struct { Name string `json:"name"` Age int `json:"age"` Email string `json:"email,omitempty"` Address Address `json:"address"`}
func main() { // Marshal a struct — Email is set, so it appears u := User{ Name: "Alice", Age: 30, Address: Address{ City: "Bangkok", Country: "Thailand", }, } data, err := json.Marshal(u) if err != nil { fmt.Println("marshal error:", err) return } fmt.Println(string(data))
// omitempty: Email is empty, so it is omitted u2 := User{Name: "Bob", Age: 25, Address: Address{City: "London", Country: "UK"}} data2, _ := json.Marshal(u2) fmt.Println(string(data2))
// Unmarshal back into a struct var result User err = json.Unmarshal(data, &result) if err != nil { fmt.Println("unmarshal error:", err) return } fmt.Printf("Name: %s, City: %s\n", result.Name, result.Address.City)
// map[string]any — flexible unmarshaling raw := `{"lang":"Go","version":1.22,"stable":true}` var m map[string]any _ = json.Unmarshal([]byte(raw), &m) fmt.Println(m["lang"], m["version"], m["stable"])}Loading Go runtime (first run only, ~8 MB)…