Golang - Data Structures - Struct Tags and Reflection

Publish date: 2025-09-20
Tags: <a href="https://programmercave.com/tags/Go/">Go</a>

Introduction

Struct tags are small pieces of metadata that you can attach to the fields of a struct. They are just strings, but they provide a way to give instructions to other Go packages that inspect your structs at runtime.

The most common use for struct tags is to control how your data is encoded to or decoded from formats like JSON, XML, or database records. This is achieved through a mechanism called reflection.


What are Struct Tags?

A struct tag is a raw string literal placed after the type in a struct field definition.

type User struct {
    Name  string `json:"name"`
    Email string `json:"email"`
    ID    int    `json:"-"` 
    // The dash means "ignore this field"
}

Anatomy of a Tag:

Analogy: Think of struct tags as sticky notes you put on the fields of a form. A note might say, “For the accounting department, call this field ‘user_id’” or “For the public API, don’t show this field at all.” The struct itself doesn’t care about the notes, but other programs (like the encoding/json package) can read them and act accordingly.


Common Use Case: JSON Marshaling

The encoding/json package is the most common consumer of struct tags.

package main

import (
	"encoding/json"
	"fmt"
)

type Product struct {
	ProductID      int     `json:"id"`
	Name           string  `json:"name"`
	Price          float64 `json:"price"`
	Published      bool    `json:"is_published,omitempty"`
	internalSecret string  // Unexported fields are always ignored
	AdminNotes     string  `json:"-"`
}

func main() {
	p1 := Product{
		ProductID:      101,
		Name:           "Go T-Shirt",
		Price:          20.50,
		Published:      true,
		internalSecret: "secret",
		AdminNotes:     "notes",
	}

	p2 := Product{
		ProductID: 102,
		Name:      "Go Mug",
		Price:     15.00,
		// Published is false (the zero value), so it will be omitted
	}

	p1Json, _ := json.MarshalIndent(p1, "", "  ")
	p2Json, _ := json.MarshalIndent(p2, "", "  ")

	fmt.Println(string(p1Json))
	fmt.Println(string(p2Json))
}

Output:

{
  "id": 101,
  "name": "Go T-Shirt",
  "price": 20.5,
  "is_published": true
}
{
  "id": 102,
  "name": "Go Mug",
  "price": 15
}

Notice how AdminNotes and internalSecret are missing, the field names match the tags, and is_published is omitted for p2.


How Does It Work? Reflection

Struct tags are meaningless to the Go compiler itself. They are just strings. Their power comes from the reflect package.

Reflection is the ability of a program to inspect its own structure at runtime. The encoding/json package uses reflection to:

  1. Iterate over the fields of a struct it’s given.
  2. For each field, check if it has a json tag.
  3. Read the value of the tag to decide the field’s name or whether to ignore it.
  4. Read the actual value of the field.
  5. Construct the final JSON output.

Reflection is a powerful but advanced feature. It is generally slower than compile-time code, which is why it’s often used in I/O-bound tasks like marshaling where the performance impact is less critical.

Interview Question: “How does JSON encoding work in Go? How can you control the output?” Answer: “It works using the reflect package. When you call json.Marshal, it inspects the struct’s fields at runtime. You can control the output by adding json struct tags to the fields to change their names, omit them if they’re empty, or ignore them completely.”


Other Uses for Struct Tags

Struct tags are a key part of what makes Go’s standard library and third-party packages so flexible and powerful.

Tags: <a href="https://programmercave.com/tags/Go/">Go</a>