Go JSON omitzero Struct Tag

Golang Tutorials


Go's encoding/json package supports an omitzero struct tag option for omitting fields whose values are zero. Added in Go 1.24, it gives you a clearer way to express "do not include this field when it has its zero value."

This is especially useful for types such as time.Time, integers, booleans, and custom types that define an IsZero() bool method. It also avoids some of the surprising behavior that can occur when omitempty is used for values whose zero state is not considered empty.

omitzero Syntax

type Item struct {
    Count int `json:"count,omitzero"`
}

When Item is marshaled to JSON, the count field is omitted when Count is 0. When Count contains a non-zero value, the field is included normally.

omitzero tests whether a field is its zero value. If the field type provides an IsZero() bool method, encoding/json uses that method to decide whether the field should be omitted.

Omit Zero Values from JSON

The following example contains an integer and a time.Time value. Both fields are omitted because they are zero-valued.

Example:

package main

import (
    "encoding/json"
    "fmt"
    "time"
)

type Event struct {
    Name      string    `json:"name"`
    Attempts  int       `json:"attempts,omitzero"`
    Published time.Time `json:"published,omitzero"`
}

func main() {
    event := Event{Name: "Launch"}

    data, err := json.Marshal(event)
    if err != nil {
        panic(err)
    }

    fmt.Println(string(data))
}

Output:

{"name":"Launch"}

omitzero vs omitempty

Both options can remove fields from JSON output, but they answer different questions. omitempty checks whether a value is considered empty by encoding/json, while omitzero checks whether it is the type's zero value.

Option Main rule Typical use
omitempty Omit values considered empty Strings, slices, maps, pointers, and other empty values
omitzero Omit values considered zero Zero-valued structs, numbers, booleans, time values, and custom IsZero rules

A key difference appears with struct values such as time.Time. A zero time value is still a struct value, so omitempty does not necessarily express the intended rule. omitzero is designed for that case.

Include a Non-Zero Value

When the field is not zero, it remains in the encoded JSON.

Example:

package main

import (
    "encoding/json"
    "fmt"
)

type Job struct {
    Name     string `json:"name"`
    Attempts int    `json:"attempts,omitzero"`
}

func main() {
    job := Job{
        Name:     "Import",
        Attempts: 2,
    }

    data, _ := json.Marshal(job)
    fmt.Println(string(data))
}

Output:

{"name":"Import","attempts":2}

Use IsZero() for Custom Types

A custom type can control its zero test by defining an IsZero() bool method. encoding/json uses that method when omitzero is present on a field of that type.

Example:

package main

import (
    "encoding/json"
    "fmt"
)

type Score int

func (s Score) IsZero() bool {
    // Treat negative scores as unset as well.
    return s <= 0
}

type Result struct {
    Name  string `json:"name"`
    Score Score  `json:"score,omitzero"`
}

func main() {
    result := Result{
        Name:  "Asha",
        Score: -1,
    }

    data, _ := json.Marshal(result)
    fmt.Println(string(data))
}

Output:

{"name":"Asha"}

Combine omitzero and omitempty

The tag options can be combined. When both are present, the field is omitted if either rule says it should be omitted.

type Profile struct {
    Nickname string `json:"nickname,omitempty,omitzero"`
}

In many cases you only need one option. Use the one that best communicates the rule your API expects.

Common Mistakes

  • Assuming omitzero changes unmarshaling: it controls marshaling output; it does not change how incoming JSON is decoded.
  • Using it on older Go versions: the option was introduced in Go 1.24, so older toolchains do not provide the same behavior.
  • Confusing zero with empty: the two concepts overlap for some types but are not identical.
  • Writing surprising IsZero methods: custom zero rules should be predictable because they directly affect serialized output.

When to Use omitzero

  • Remove zero-valued timestamps from API responses.
  • Omit counters, flags, or numeric fields that have not been set.
  • Define domain-specific "unset" behavior with IsZero().
  • Make JSON output rules more explicit than relying on omitempty.

Recommended Practices

  • Use omitzero when the business rule is specifically based on a type's zero value.
  • Keep custom IsZero() implementations simple and documented.
  • Add JSON tests for zero and non-zero examples so API output remains stable.
  • Use pointers when you must distinguish "not provided" from an explicitly supplied zero value.

Conclusion

The omitzero JSON tag gives Go programs a direct way to omit zero-valued fields during marshaling. It works naturally with built-in zero values, improves handling for struct values such as time.Time, and can be customized through IsZero(). Choose it when "zero" is the rule you want your JSON API to express.



Found This Page Useful? Share It!
Get the Latest Tutorials and Updates
Join us on Telegram