How do struct tags work, and how are they used with reflection?
Quick Answer
A struct tag is a string literal attached to a struct field, written after its type: Name string \json:"name" validate:"required"`. Tags are just metadata — Go itself does nothing with them at compile time. Libraries read them at runtime through the reflectpackage'sStructField.Tag and a small parsing convention (key:"value"pairs).encoding/jsonreadsjson:"..." tags to control field names, omission (omitempty), and skipping (json:"-"); validation libraries read their own tag keys the same way. Because tags are plain strings, a typo like jsno:"name"` compiles fine but silently does nothing, which is the most common tag-related bug.
Detailed Answer
Struct tags are how Go bolts on metadata-driven behavior, like JSON field names, without adding any new syntax to the language itself.
A typical tagged struct
type User struct {
ID int `json:"id"`
Name string `json:"name"`
Email string `json:"email,omitempty"`
Password string `json:"-"` // never serialized
}
u := User{ID: 1, Name: "Alice", Password: "secret"}
b, _ := json.Marshal(u)
fmt.Println(string(b)) // {"id":1,"name":"Alice"}
omitempty skips the field if it holds its zero value; json:"-" skips it unconditionally, which is exactly how you keep a sensitive field like a password hash out of API responses.
How a library actually reads a tag
t := reflect.TypeOf(User{})
field, _ := t.FieldByName("Name")
fmt.Println(field.Tag.Get("json")) // "name"
encoding/json, and most tag-driven libraries, use reflect to inspect each field's Tag string at runtime and parse out the value for the key they care about (json, validate, db, etc.).
The silent-failure gotcha
type User struct {
Name string `jsno:"name"` // typo: key should be "json"
}
This compiles cleanly — the tag is just a string literal, and the compiler doesn't know or care what keys are meaningful. encoding/json simply won't find a json tag on this field, and falls back to using the Go field name (Name) as the JSON key instead. There's no compiler warning for a misspelled tag key, which makes careful review (or a linter that understands struct tags) worthwhile.