go generate & stringer
go generate orchestrates code generators.
Search across all documentation pages
go generate orchestrates code generators.
stringer is the hello-world generator: typed constants get a correct String() method without reflection.
Place //go:generate comments above functions or types in any .go file.
Run go generate ./... from module root to execute those commands.
stringer emits a *_string.go file with String() for int-based enums.
Teams commit generated output and rerun generators when types change.
Quick-reference generate workflow.
//go:generate stringer -type=Status -trimprefix=Status
type Status int
const (
StatusPending Status = iota
StatusActive
StatusDone
)go install golang.org/x/tools/cmd/stringer@latest
go generate ./...
go test ./...When to reach for this:
String() without maintaining switch statements by handgo generate tool (mockgen, protobuf, stringer)Full mini-module with stringer output checked in.
// status.go
package job
//go:generate stringer -type=Status -trimprefix=Status
type Status int
const (
StatusPending Status = iota
StatusRunning
StatusFailed
StatusSucceeded
)
func (s Status) IsTerminal() bool {
return s == StatusFailed || s == StatusSucceeded
}After go generate:
// status_string.go (generated)
package job
import "strconv"
func _() {
_ = x[StatusPending-0]
}
const _Status_name = "PendingRunningFailedSucceeded"
var _Status_index = [...]uint8{0, 7, 14, 20, 29}
func (i Status) String() string {
if i < 0 || i >= Status(len(_Status_index)-1) {
return "Status(" + strconv.FormatInt(int64(i), 10) + ")"
}
return _Status_name[_Status_index[i]:_Status_index[i+1]]
}// job_test.go
package job
import "testing"
func TestStatusString(t *testing.T) {
if StatusRunning.String() != "Running" {
t.Fatal(StatusRunning.String())
}
}What this demonstrates:
-trimprefix removes redundant Status prefix from string outputDO NOT EDIT header (stringer adds it)Status(99) fallback string.go files for lines starting with //go:generate$GOFILE and $GOPACKAGE set to the containing file| Tool | Directive example | Output |
|---|---|---|
| stringer | //go:generate stringer -type=T | t_string.go |
| mockgen | //go:generate mockgen -source=iface.go | mock_iface.go |
| protobuf | //go:generate protoc --go_out=. api.proto | api.pb.go |
| enumer | third-party enum helpers | custom |
go generate ./...
git diff --exit-code || (echo "run go generate and commit"; exit 1)// Keep generators in tools module or tools.go with build tag
//go:build tools
package tools
import _ "golang.org/x/tools/cmd/stringer"-type list. Fix: Separate //go:generate lines per type.golang.org/x/tools version in tools.go for reproducible CI. Fix: go install at pinned module version in CI.| Alternative | Use When | Don't Use When |
|---|---|---|
Hand-written String() | One or two constants | Large enums change often |
fmt.Sprintf("%d") | Debug only | Logs and APIs need names |
| iota + map | Tiny enums without tooling | You already use stringer elsewhere |
| protobuf enums | gRPC services | Plain Go domain types |
No.
Invoke it explicitly in CI or local scripts.
Most Go projects yes, so consumers build without generator tools.
Document the regenerate command in README or CONTRIBUTING.
Strips a prefix from constant names in the generated string.
StatusRunning becomes "Running" with -trimprefix=Status.
Yes: stringer -type=Foo,Bar or multiple directives.
Any .go file in the package, commonly next to the type definition.
Use a tools.go with build tag tools and install that module version in CI.
Fix the generator command, missing protoc plugins, or PATH.
Log $GOFILE for the failing directive.
No.
It is a compile-time code generator using go/types.
Yes.
Different purposes: generate creates files; fix modernizes call sites.
Run both on upgrade branches.
Table-test known constants and one out-of-range value.
Stack versions: This page was written for Go 1.26.x (Green Tea GC default, go fix modernizers - verify patch at build), chi (latest - verify at build), gin (latest - verify at build), echo (latest - verify at build), google.golang.org/grpc (latest - verify at build), sigs.k8s.io/controller-runtime (latest - verify at build), kubebuilder (latest - verify at build), tinygo (latest - verify board targets at build), wazero (latest - verify at build), and golangci-lint (latest - verify linter set at build).
Reviewed by Chris St. John·Last updated Jul 19, 2026