If you want to print struct golang values while debugging, you usually reach for fmt.Printf first, then switch to JSON when you need a golang pretty print struct layout for APIs or logs. The same ideas apply when people say go print struct or golang print object—they mean “show me the fields.” This page covers golang printf struct verbs (%v, %+v, %#v), pretty print struct golang with encoding/json, golang print type of variable with %T and reflect.TypeOf, the fmt.Stringer hook, and optionally go-spew for deep dumps. For struct basics, see structs in Go; for JSON tags and decoding, see parse JSON in Go.
Checked with Go 1.24 on 64-bit Linux (Fedora and Ubuntu family).
golang print struct with fmt and encoding/json
golang printf struct: %v, %+v, %#v, and %T
The fmt package is the fastest way to print struct golang values to the terminal:
%v— default value format (compact struct without field names in this mode).%+v— adds field names for structs (what many people mean by pretty print struct golang in plain text).%#v— Go-syntax representation, useful when you want something you could paste back into code.%T— dynamic type of the operand; answers golang print type of variable for concrete values.
package main
import (
"encoding/json"
"fmt"
"reflect"
)
type Person struct {
ID int
Name string
Phone string
}
func main() {
p := Person{1, "Anna", "+125639842"}
fmt.Printf("%%v: %v\n", p)
fmt.Printf("%%+v: %+v\n", p)
fmt.Printf("%%#v: %#v\n", p)
fmt.Printf("%%T: %T\n", p)
fmt.Println(reflect.TypeOf(p))
b, err := json.MarshalIndent(p, "", " ")
if err != nil {
panic(err)
}
fmt.Printf("json:\n%s\n", string(b))
}You should see {1 Anna ...} for %v, field names for %+v, a main.Person{...} literal for %#v, main.Person for %T, the same type from reflect.TypeOf, and indented JSON at the end.
golang pretty print struct as JSON
json.MarshalIndent is the usual golang pretty print struct choice when humans read the output. Only exported fields (names starting with an uppercase letter) are marshaled; unexported fields are omitted silently unless you use custom MarshalJSON logic.
golang print type of variable and interfaces
For a concrete variable p, %T and reflect.TypeOf(p) agree on the static type. For an interface{} / any holding different concrete types, %T prints the dynamic type. Combine that with a type switch when you need different formatting per case.
fmt.Stringer instead of a custom ToString
The idiomatic hook for go print struct output used by fmt.Print and friends is String() string, not a Java-style toString name:
package main
import "fmt"
type Person struct {
ID int
Name string
}
func (p Person) String() string {
return fmt.Sprintf("Person(%s)", p.Name)
}
func main() {
fmt.Println(Person{1, "Anna"})
}You should see a single line starting with Person(.
Optional: deep dumps with go-spew
For interactive debugging, spew.Dump walks nested values and annotates lengths and pointers. It lives outside the standard library, so add a dependency and run locally:
go get github.com/davecgh/go-spew@v1.1.1package main
import "github.com/davecgh/go-spew/spew"
type Person struct {
ID int
Name string
}
func main() {
spew.Dump(Person{1, "Anna"})
}Expect labeled fields, string lengths, and pointer addresses in the style of spew’s formatter.
Summary
Golang print struct workflows usually start with golang printf struct verbs: %+v for field names, %#v for Go syntax, %T or reflect.TypeOf for golang print type of variable. Pretty print struct golang output for humans often means json.MarshalIndent, remembering JSON only sees exported fields. For stable one-line logs, implement fmt.Stringer. Go print object phrasing maps to the same tools once you know the concrete type behind an interface. Third-party go-spew remains handy for dense debugging dumps when plain fmt is not enough.

