Code Generation and Embedding
Overview
go generate runs commands to generate code, and //go:embed embeds files into binaries.
go generate
//go:generate stringer -type=Status
type Status int
const (
Pending Status = iota
Approved
Rejected
)go generate ./...Common Generators
stringer- String methods for enumsmockgen- Mock interfaces for testingprotoc- Protocol buffer code
Embedding Files
import "embed"
//go:embed config.json
var configData []byte
//go:embed templates/*
var templates embed.FS
//go:embed static
var staticFiles embed.FSReading Embedded Files
//go:embed data.txt
var data string // As string
//go:embed data.bin
var data []byte // As bytes
//go:embed files/*
var fs embed.FS // As filesystem
content, _ := fs.ReadFile("files/config.json")HTTP File Server
//go:embed static/*
var static embed.FS
func main() {
fs := http.FileServer(http.FS(static))
http.Handle("/static/", fs)
http.ListenAndServe(":8080", nil)
}Templates
//go:embed templates/*.html
var templates embed.FS
tmpl := template.Must(template.ParseFS(templates, "templates/*.html"))Summary
| Directive | Purpose |
|---|---|
//go:generate cmd |
Run code generator |
//go:embed file |
Embed as string/bytes |
//go:embed dir/* |
Embed as filesystem |
Worked example
Generate a tiny constants file at runtime (stand-in for go generate output), then use it.
Save as main.go. Then:
go mod init example
go run .package main
import (
"fmt"
"strings"
)
func generateVersionGo(version string) string {
return fmt.Sprintf("// Code generated by demo; DO NOT EDIT.\npackage main\n\nconst GeneratedVersion = %q\n", version)
}
func main() {
src := generateVersionGo("1.2.3")
// Real workflows write this via //go:generate (stringer, sqlc, mockgen, …).
fmt.Println(strings.TrimSpace(src))
fmt.Println("lines:", strings.Count(src, "\n"))
}Expected output:
// Code generated by demo; DO NOT EDIT.
package main
const GeneratedVersion = "1.2.3"
lines: 4
More examples
//go:embed string + FS in one program (needs a local file).
printf 'hi' > note.txtpackage main
import (
"embed"
"fmt"
)
//go:embed note.txt
var note string
//go:embed note.txt
var fs embed.FS
func main() {
fmt.Println("string:", note)
b, _ := fs.ReadFile("note.txt")
fmt.Println("fs:", string(b))
}Expected output:
string: hi
fs: hi
Runnable example
Save as main.go and create a sibling hello.txt with the text embedded hello. Then:
go mod init example
printf 'embedded hello' > hello.txt
go run .package main
import (
"embed"
"fmt"
"io/fs"
"strings"
)
//go:embed hello.txt
var hello string
//go:embed hello.txt
var helloBytes []byte
//go:embed hello.txt
var content embed.FS
// version is normally produced by go:generate; pure-Go fallback for this demo.
var version = "dev"
func main() {
fmt.Println("embed string:", hello)
fmt.Println("embed bytes:", string(helloBytes))
b, err := content.ReadFile("hello.txt")
if err != nil {
panic(err)
}
fmt.Println("embed FS:", string(b))
// Walk the embedded FS (handy for static assets)
_ = fs.WalkDir(content, ".", func(path string, d fs.DirEntry, err error) error {
if err != nil || d.IsDir() {
return err
}
fmt.Println("walk:", path)
return nil
})
// Stand-in for generated code: a tiny template expansion
generated := strings.ReplaceAll(
"// Code generated by demo; DO NOT EDIT.\nconst Version = \"{{V}}\"\n",
"{{V}}",
version,
)
fmt.Println(strings.TrimSpace(generated))
}Expected output:
embed string: embedded hello
embed bytes: embedded hello
embed FS: embedded hello
walk: hello.txt
// Code generated by demo; DO NOT EDIT.
const Version = "dev"
What to notice: //go:embed paths are relative to the source file and bake content into the binary—no runtime file needed after build. Real go generate tools (stringer, sqlc, mockgen) write Go you commit or produce in CI; keep generators deterministic.
Try next: Embed a static/* directory and serve it with http.FileServer(http.FS(static)) via httptest. Add a //go:generate echo package main > zzz_gen.go and run go generate.