encoding/json converts Go values to and from JSON. Struct tags control field names and omission, and a type can take over its own encoding by implementing Marshaler or Unmarshaler.
Marshal walks a value and produces its JSON encoding; only exported fields are visible to it. Unmarshal reverses the process into a value pointed to by its second argument.
type Point struct {
X, Y int
}
p := Point{X: 3, Y: 4}
b, err := json.Marshal(p)
if err != nil {
log.Fatal(err)
}
fmt.Println(string(b))
var p2 Point
json.Unmarshal(b, &p2)
fmt.Println(p2)Without a json tag, a field's Go name becomes its JSON key exactly as written, capital letter included.
$ go run main.go
{"X":3,"Y":4}
{3 4}Try it
Examples
Exported fields become JSON keys, using the json tag name when one is set. Unexported fields, and empty ones tagged omitempty, are left out.
type Person struct {
Name string `json:"name"`
Age int `json:"age,omitempty"`
email string // unexported, always ignored
}
p := Person{Name: "Ada"}
b, _ := json.Marshal(p)
fmt.Println(string(b)){"name":"Ada"}Unmarshal matches JSON object keys to struct fields by tag name, falling back to a case-insensitive match on the field name.
data := `{"name":"Ada","age":36}`
var p Person
json.Unmarshal([]byte(data), &p)
fmt.Printf("%+v\n", p){Name:Ada Age:36 email:}Unmarshaling into an any produces bool, float64, string, []any, map[string]any, or nil, one per JSON kind.
var v any
json.Unmarshal([]byte(`{"a":1,"b":[true,null,"x"]}`), &v)
m := v.(map[string]any)
fmt.Println(m["a"], m["b"])1 [true x] Decode can be called repeatedly on the same Decoder to pull consecutive JSON values off a stream, stopping at io.EOF.
dec := json.NewDecoder(strings.NewReader(`{"n":1}{"n":2}{"n":3}`))
for {
var m struct{ N int `json:"n"` }
if err := dec.Decode(&m); err == io.EOF {
break
}
fmt.Println(m.N)
}1
2
3RawMessage defers parsing part of a document, useful when a field's shape depends on a sibling field like Kind here.
type Wrapper struct {
Kind string `json:"kind"`
Data json.RawMessage `json:"data"`
}
raw := []byte(`{"kind":"point","data":{"x":3,"y":4}}`)
var w Wrapper
json.Unmarshal(raw, &w)
fmt.Println(w.Kind, string(w.Data))point {"x":3,"y":4}Reference
| Function | Description |
|---|---|
Marshal(v any) ([]byte, error) json.Marshal(Point{3, 4}) // {"X":3,"Y":4}, nil | Encodes v as JSON, using exported struct fields, json tags, and any Marshaler or encoding.TextMarshaler implementation. |
MarshalIndent(v any, prefix, indent string) ([]byte, error) | Like Marshal, but formats the output with the given prefix and indent applied at each nesting level. |
Unmarshal(data []byte, v any) error | Decodes JSON data into the value pointed to by v, which must be a non-nil pointer. |
Valid(data []byte) bool | Reports whether data is syntactically valid JSON, without decoding it into any Go value. |
Compact(dst *bytes.Buffer, src []byte) error | Appends src to dst with insignificant whitespace removed. |
Indent(dst *bytes.Buffer, src []byte, prefix, indent string) error | Appends an indented form of the JSON in src to dst, one element per line. |
HTMLEscape(dst *bytes.Buffer, src []byte) | Appends src to dst with <, >, &, and the U+2028/U+2029 line separators escaped, safe for embedding inside an HTML <script> tag. |
NewDecoder(r io.Reader) *Decoder | Returns a Decoder that reads and parses JSON values from r as they're needed, instead of buffering everything up front. |
(*Decoder) Decode(v any) error | Reads the next JSON value from the stream into v; returns io.EOF once the stream is exhausted. |
(*Decoder) More() bool | Reports whether another element remains in the array or object currently being parsed. |
(*Decoder) Token() (Token, error) | Returns the next JSON token, a Delim, bool, float64, Number, string, or nil, for walking the structure manually. |
(*Decoder) DisallowUnknownFields() | Makes Decode return an error when the JSON has object keys with no matching exported struct field, instead of ignoring them. |
(*Decoder) UseNumber() | Makes Decode store JSON numbers as a Number instead of float64 when decoding into an any or map[string]any. |
(*Decoder) Buffered() io.Reader | Returns a reader over the data the Decoder has already buffered but not yet consumed. |
(*Decoder) InputOffset() int64 | Returns the current byte offset into the input stream, marking where the next token begins. |
NewEncoder(w io.Writer) *Encoder | Returns an Encoder that writes successive JSON values to w. |
(*Encoder) Encode(v any) error | Writes the JSON encoding of v to the stream, followed by a newline. |
(*Encoder) SetEscapeHTML(on bool) | Toggles the default HTML-safe escaping of &, <, and > inside string values; disable it for non-HTML output. |
(*Encoder) SetIndent(prefix, indent string) | Formats every subsequent Encode call as if passed through Indent; SetIndent("", "") turns indentation back off. |
type Number string | Holds the literal text of a JSON number when a Decoder is set to UseNumber, preserving precision a float64 would lose. |
(Number) Float64() (float64, error) | Parses the number as a float64. |
(Number) Int64() (int64, error) | Parses the number as an int64. |
(Number) String() string | Returns the number's original literal text, unchanged. |
type Delim rune | One of the four JSON structural characters, [ ] { }, returned by Decoder.Token. |
(Delim) String() string | Returns the delimiter as a one-character string. |
type Token any | Holds one decoded value from Decoder.Token: a Delim, bool, float64, Number, string, or nil. |
type RawMessage = jsontext.Value | A []byte alias that marshals as its literal JSON content and unmarshals by copying the raw bytes verbatim, useful for delaying or precomputing part of a document. |
type Marshaler = jsonv2.Marshaler | Interface with MarshalJSON() ([]byte, error); implementing it lets a type control its own JSON encoding. |
type Unmarshaler = jsonv2.Unmarshaler | Interface with UnmarshalJSON([]byte) error; implementing it lets a type control how it's decoded from JSON. |
type SyntaxError struct{ Offset int64 } | Returned by Unmarshal when the input isn't syntactically valid JSON; Offset marks how many bytes were read before the error. |
type UnmarshalTypeError struct{ Value, Type, Offset, Struct, Field, Err } | Returned when a JSON value can't be assigned to the target Go type; the fields describe what went wrong and where. |
(*UnmarshalTypeError) Unwrap() error | Exposes any underlying Err, so errors.Is and errors.As can see through it. |
type InvalidUnmarshalError struct{ Type reflect.Type } | Returned when Unmarshal is passed something other than a non-nil pointer. |
type UnsupportedTypeError struct{ Type reflect.Type } | Returned by Marshal for Go types JSON has no representation for, such as channels or functions. |
type UnsupportedValueError struct{ Value, Str } | Returned by Marshal for values JSON can't represent, such as a NaN or infinite float. |
type MarshalerError struct{ Type reflect.Type; Err error } | Wraps an error returned from a type's own MarshalJSON or MarshalText method. |
(*MarshalerError) Unwrap() error | Returns the underlying error from the failed marshal method. |
type InvalidUTF8Error struct{ S string } | Deprecated: no longer returned. Marshal now repairs invalid UTF-8 instead of erroring; kept for source compatibility. |
type UnmarshalFieldError struct{ Key, Type, Field } | Deprecated: no longer returned. Kept only for source compatibility. |
DefaultOptionsV1() Options | Returns the full bundle of options that reproduces this package's historical v1 behavior; what Marshal and Unmarshal use internally. |
CallMethodsWithLegacySemantics(v bool) Options | Controls whether pointer-receiver marshal methods require an addressable value and whether map keys skip Marshaler/Unmarshaler, matching v1's rules. |
FormatByteArrayAsArray(v bool) Options | Controls whether a fixed-size [N]byte encodes as a JSON array of numbers (v1) instead of a base64 string (v2 default). |
FormatBytesWithLegacySemantics(v bool) Options | Controls whether named byte-slice types are treated as binary data the way v1 always did. |
FormatDurationAsNano(v bool) Options | Controls whether a time.Duration encodes as a plain JSON number of nanoseconds (v1) rather than erroring (v2 default). |
MatchCaseSensitiveDelimiter(v bool) Options | Controls whether case-insensitive field matching also normalizes underscores and dashes, as v1 does. |
MergeWithLegacySemantics(v bool) Options | Controls how unmarshaling into a non-zero Go value merges versus replaces, matching v1's inconsistencies. |
OmitEmptyWithLegacySemantics(v bool) Options | Controls whether omitempty means "Go zero value" (v1) instead of "encodes as an empty JSON value" (v2 default). |
ParseBytesWithLooseRFC4648(v bool) Options | Controls whether base64/base32 decoding tolerates stray \r and \n characters, as v1 does. |
ParseTimeWithLooseRFC3339(v bool) Options | Controls whether time.Time parsing accepts historically tolerated RFC 3339 deviations instead of the strict grammar. |
ReportErrorsWithLegacySemantics(v bool) Options | Controls whether errors come back as the familiar SyntaxError, UnmarshalTypeError, and friends instead of v2's unified error types. |
StringifyWithLegacySemantics(v bool) Options | Controls whether the string tag option can stringify bools and strings, not just numbers. |
UnmarshalArrayFromAnyLength(v bool) Options | Controls whether a Go array can unmarshal from a JSON array of a different length instead of requiring an exact match. |
Struct tags
A tag's first part renames the field; omitempty drops it when the value is the Go zero value or empty; omitzero drops it when a type-specific IsZero check (or the zero value) says it's empty; string quotes a number, bool, or string as JSON text; - excludes the field entirely.
type Item struct {
Name string `json:"name"`
Price float64 `json:"price,omitempty"`
SKU string `json:"sku,omitzero"`
Count int `json:",string"`
Note string `json:"-"`
}A type that implements MarshalJSON and UnmarshalJSON controls its own representation completely, overriding whatever the default struct or basic-type encoding would have produced.
type Status int
const (
Pending Status = iota
Active
Done
)
func (s Status) MarshalJSON() ([]byte, error) {
names := [...]string{"pending", "active", "done"}
return json.Marshal(names[s])
}
func (s *Status) UnmarshalJSON(b []byte) error {
var name string
if err := json.Unmarshal(b, &name); err != nil {
return err
}
switch name {
case "active":
*s = Active
case "done":
*s = Done
default:
*s = Pending
}
return nil
}v1 and v2
New code that wants the stricter v2 defaults, such as rejecting duplicate object keys or refusing invalid UTF-8, can import encoding/json/v2 directly. This page covers the v1 package, which remains the stable, fully supported default.
// encoding/json (this package) is the v1 API and stays fully supported.
// It's now implemented on top of the newer encoding/json/v2 package,
// with Options and DefaultOptionsV1 bridging the two for callers who
// invoke jsonv2.Marshal or jsonv2.Unmarshal directly.
import jsonv2 "encoding/json/v2"
b, err := jsonv2.Marshal(v, json.DefaultOptionsV1())Putting it together
A custom MarshalJSON takes over encoding for its field; Unmarshal calls the matching UnmarshalJSON automatically, so the caller never touches the string representation directly.
type Task struct {
Title string `json:"title"`
Status Status `json:"status"`
}
t := Task{Title: "ship it", Status: Active}
b, _ := json.Marshal(t)
fmt.Println(string(b))
var t2 Task
json.Unmarshal([]byte(`{"title":"ship it","status":"done"}`), &t2)
fmt.Println(t2.Title, t2.Status)Status has no String method for fmt, so printing it directly shows the underlying int rather than the JSON name.
$ go run main.go
{"title":"ship it","status":"active"}
ship it 2