The fmt Package in Go and Its Full List of Print Verbs
Every fmt verb worth knowing in one table with real output: %v, %+v and %#v, numbers, strings, width and flags, and the error markers.

fmt is the first package every Go program imports and the one whose documentation people rarely read to the end. Most of the time %v and %d are enough. This page is the whole list, grouped by what you are printing, each with the output Go 1.25 produced for it, so you can find a verb by what it looks like. The program that produced the output is at the bottom, and the rows that go wrong on purpose are collected in a table at the end. It is a companion to formatting time and print a struct in a debug friendly way, and part of the Go basics path.
Tested with Go 1.25.6, macOS on Apple Silicon (arm64)
General verbs: any value
| Verb | Prints | Example output for User{"ada", 36, ["x"]} |
|---|---|---|
%v | The default format | {ada 36 [x]} |
%+v | Struct with field names | {Name:ada Age:36 tags:[x]} |
%#v | Go syntax, with type | main.User{Name:"ada", Age:36, tags:[]string{"x"}} |
%T | The type | main.User |
%% | A literal percent sign | % |
A pointer to a struct prints as &{ada 36 [x]} with %v, and with field names for %+v. Maps print in sorted key order, map[a:1 b:2], regardless of insertion order, which makes output stable. Slices print as [1 2], a nil pointer as <nil>, and a nil interface as <nil> too.
Integers, characters and booleans
| Verb | Prints | Output |
|---|---|---|
%d | Decimal | 255 |
%b | Binary | 101 for 5 |
%o | Octal | 10 for 8 |
%O | Octal with 0o prefix | 0o10 for 8 |
%x, %X | Hex, lower or upper | ff, FF |
%c | The character for a code point | G |
%q | A quoted character | 'G' |
%U | Unicode notation | U+0047 |
%t | A boolean | true |
Floating point
| Verb | Prints | Output for the shown value |
|---|---|---|
%f | Decimal, six digits by default | 3.141590 for 3.14159 |
%.2f | Two digits after the point | 3.14 |
%8.3f | Width 8, three digits | 3.142 |
%e | Scientific | 1.234568e+05 for 123456.789 |
%g | The shortest of %e and %f that is exact | 123456.789, and 1e+21 for 1e21 |
%g is what %v uses for floats, so fmt.Println(0.1) prints 0.1. For money display, use %.2f, and remember that formatting rounds the output and not the value, a point made in the floating point article.
Strings and bytes
| Verb | Prints | Output |
|---|---|---|
%s | The string, or a []byte as text | go, hi |
%q | Double quoted and escaped | "go" |
%x | Hex of each byte | 676f for "go" |
% x | Hex with spaces between bytes | 67 6f |
%10s | Right aligned in 10 columns | go |
%-10s | Left aligned in 10 columns | go |
For a []byte, %v prints the numbers, [104 105], and %s prints the text, which is the most common surprise when printing bytes. For a []string, %q quotes each element, which makes empty strings and spaces visible, and I use it whenever I debug a list of strings.
Width, precision and flags
Between the % and the verb, three optional parts control layout: flags, width and precision. A * takes the width or precision from an argument.
| Write | Meaning | Output |
|---|---|---|
%5d | Width 5, right aligned | [ 42] |
%-5d | Left aligned | [42 ] |
%05d | Zero padded | [00042] |
%+d | Always show the sign | [+42] |
%#x | Add the 0x prefix | 0xbee |
%#o | Add the 0 prefix | 010 |
%*d | Width taken from an argument | 42 for width 6 |
%[2]s %[1]s | Pick arguments by position | b a |
%6.2f%% | Width, precision and a literal percent | 12.35% |
The explicit argument index %[1]s is useful when the same value appears twice in a format, as in "%[1]s: %[1]q", and when translating messages whose word order differs.
Types with methods
If a value has a String() string method, %v and %s call it, and %d still prints the underlying number. Errors with an Error() string method print through it for %v and %s. Use %w instead of %v inside fmt.Errorf to wrap an error so errors.Is and errors.As can find it. The catch with pointer receivers is covered in the pointer receiver error: a String on *T is not called when you print a T.
What the output looked like
All of the above came from one program. The wrong ones are on purpose, to show the markers:
package main
import (
"errors"
"fmt"
)
type User struct {
Name string
Age int
tags []string
}
type Level int
func (l Level) String() string { return [...]string{"low", "high"}[l] }
func main() {
u := User{"ada", 36, []string{"x"}}
p := &u
fmt.Printf("%v | %+v | %#v | %T\n", u, u, u, u)
fmt.Printf("%v | %+v\n", p, p)
fmt.Printf("%d %b %o %x %X %c %q %U\n", 255, 5, 8, 255, 255, 'G', 'G', 'G')
fmt.Printf("%f %.2f %8.3f %e %g %g\n", 3.14159, 3.14159, 3.14159, 123456.789, 123456.789, 1e21)
fmt.Printf("%s %q %x % x %10s|%-10s|\n", "go", "go", "go", "go", "go", "go")
fmt.Printf("%t %v %5t|\n", true, false, true)
fmt.Printf("[%5d] [%-5d] [%05d] [%+d] [%x] [%#x] [%#o]\n", 42, 42, 42, 42, 3054, 3054, 8)
fmt.Printf("%v %d %s %q\n", Level(1), Level(1), Level(1), Level(1))
fmt.Printf("%[2]s %[1]s %[2]s\n", "a", "b")
fmt.Printf("%*d|%-*d|\n", 6, 42, 6, 42)
fmt.Printf("%d %s\n", "text", 5)
fmt.Printf("%d\n")
fmt.Printf("%d\n", 1, 2)
fmt.Printf("%v %v %v\n", []int{1, 2}, map[string]int{"b": 2, "a": 1}, [2]bool{true})
fmt.Printf("%q %v\n", []string{"a b", "c"}, []byte("hi"))
fmt.Printf("%s %x\n", []byte("hi"), []byte("hi"))
err := fmt.Errorf("load: %w", errors.New("disk full"))
fmt.Printf("%v | %q\n", err, err)
fmt.Printf("100%%\n")
fmt.Println("a", 1, 2, "b", "c", 3.0, nil)
fmt.Print("a", 1, 2, "b", "c", 3.0, "\n")
fmt.Printf("%6.2f%%\n", 12.3456)
}{ada 36 [x]} | {Name:ada Age:36 tags:[x]} | main.User{Name:"ada", Age:36, tags:[]string{"x"}} | main.User
&{ada 36 [x]} | &{Name:ada Age:36 tags:[x]}
255 101 10 ff FF G 'G' U+0047
3.141590 3.14 3.142 1.234568e+05 123456.789 1e+21
go "go" 676f 67 6f go|go |
true false true|
[ 42] [42 ] [00042] [+42] [bee] [0xbee] [010]
high 1 high "high"
b a b
42|42 |
%!d(string=text) %!s(int=5)
%!d(MISSING)
1
%!(EXTRA int=2)[1 2] map[a:1 b:2] [true false]
["a b" "c"] [104 105]
hi 6869
load: disk full | "load: disk full"
100%
a 1 2 b c 3 <nil>
a1 2bc3
12.35%Note the three markers that begin with %! in the output. A verb that does not fit its argument prints %!d(string=text), with the verb, the actual type and the value, instead of panicking, since a logging call that crashes the program is worse than one that prints something odd. A format with no matching argument prints %!d(MISSING). An argument with no verb, as in the second %d line, prints %!(EXTRA int=2) after the format's own newline, so the marker lands at the start of whatever prints next, in front of the slice line here. None of these stops the program, which is why they survive in production. go vet knows the format verbs and reports all three before you ship:
go vet ./...Print, Println and Printf
Println writes its operands separated by spaces and ends with a newline, whatever the types. Print adds a space between operands only when neither is a string, so a call mixing strings and numbers, as in the last two print lines above, runs the strings together while the numbers keep their spaces: a1 2bc3. That is an odd rule, and the reason to use Println or Printf unless you have a specific need. Sprintf returns a string, Fprintf writes to an io.Writer such as a file or a strings.Builder, and Errorf builds an error. The S, F and Errorf variants all take the same verbs.
What is not on this list
The scanning side, fmt.Sscanf and fmt.Fscan, uses a related but smaller set of verbs and is rarely the right tool for parsing; reading user input and strconv are better. Custom formatting for a type is possible by implementing Format(f fmt.State, verb rune), which almost no code needs, and GoStringer changes what %#v prints. For structured logs, use log/slog and pass key and value pairs instead of building a message string. The complete rules, including every flag, are in the fmt package documentation, and the go vet printf check explains what it can and cannot detect.


