Introduction
A struct tag is a string of metadata attached to a struct field, written using backticks immediately after the field's type. Tags themselves do nothing on their own; the Go compiler stores them as plain string data attached to field metadata. Their power comes from packages that read tags via reflection at runtime, such as encoding/json for JSON marshaling, database/sql style ORMs, and validation libraries, to control how a field is serialized, mapped, or validated.
Cricket analogy: A struct tag is like a label on a player's kit bag noting their squad number, meaningless to the bag itself but read by the team's equipment manager, similarly libraries like encoding/json use reflection at runtime to read tags and control serialization.
Syntax
type User struct {
ID int `json:"id"`
Name string `json:"name"`
Email string `json:"email,omitempty"`
Password string `json:"-"`
}Explanation
Each tag is written as a backtick-quoted string containing space-separated key:"value" pairs. The convention, by the encoding/json package, is that json:"name" renames the field in JSON output, the omitempty option skips the field if it holds a zero value, and json:"-" excludes the field entirely from JSON output. Tags are read at runtime using the reflect package: reflect.TypeOf(v).Field(i).Tag.Get("json") returns the tag's value as a plain string. Because tags are just strings, the compiler does not validate their contents; a typo in a tag will not cause a compile error, only unexpected runtime behavior.
Cricket analogy: A tag like json:"name" is like renaming a player's display name on the scoreboard from their given name, omitempty is like skipping a stat line that's still zero, json:"-" is like hiding a player entirely from the public sheet, and reflect.TypeOf reads that label at match time; a typo just silently misnames the display.
Example
package main
import (
"encoding/json"
"fmt"
)
type User struct {
ID int `json:"id"`
Name string `json:"name"`
Email string `json:"email,omitempty"`
}
func main() {
u := User{ID: 1, Name: "Ada"}
b, _ := json.Marshal(u)
fmt.Println(string(b))
}Output
{"id":1,"name":"Ada"}Key Takeaways
- Struct tags are backtick-delimited metadata strings attached to struct fields.
- They are inert to the compiler and only interpreted by libraries using reflection.
- encoding/json uses tags to rename fields, omit empty values, or skip fields entirely.
- Tag typos are not caught at compile time, only surfaced as runtime behavior differences.
Practice what you learned
1. Where does the Go compiler enforce validation of struct tag contents?
2. What mechanism do libraries like encoding/json use to read struct tags at runtime?
3. In `Email string \`json:"email,omitempty\`", what does omitempty do?
4. What does the tag `json:"-"` mean for a struct field?
Was this page helpful?
You May Also Like
Structs in Go
A composite type that groups related fields together, forming the basis for custom data modeling in Go.
Struct and Interface Embedding in Go
Understand how Go uses struct and interface embedding to compose behavior instead of using inheritance.
Interfaces in Go
Learn how Go interfaces define behavior through implicit, structural typing without classes or inheritance.
Related Reading
Related Study Notes in Programming
Browse all study notesApache Spark Study Notes
Programming · 30 topics
ProgrammingApache Flink Study Notes
Programming · 30 topics
ProgrammingHadoop Study Notes
Programming · 30 topics
ProgrammingSnowflake Study Notes
Programming · 30 topics
ProgrammingApache Airflow Study Notes
Programming · 30 topics
Programmingdbt (Data Build Tool) Study Notes
Programming · 30 topics