HowtoGo
Home / Standard Library / encoding/json
Standard Library

encoding/json

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.

Terminal
$ 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))
Output
{"name":"Ada"}

Reference

FunctionDescription
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.

Terminal
$ go run main.go
{"title":"ship it","status":"active"}
ship it 2