go / embed
I use //go:embed to bundle files into a Go binary at compile time.
Single file
Embed a single file as a byte slice:
import _ "embed"
//go:embed schema.sql
var schema []byte
func initDB(db *sql.DB) error {
_, err := db.Exec(string(schema))
return err
}
Or as a string:
//go:embed version.txt
var version string
Multiple files
Embed multiple files into an embed.FS:
import "embed"
//go:embed templates/*.html
var templatesFS embed.FS
func loadTemplate(name string) ([]byte, error) {
return templatesFS.ReadFile("templates/" + name)
}
The path in ReadFile must match the embedded path exactly,
including the directory prefix.
Patterns
Patterns work like filepath.Glob:
//go:embed static/*
var staticFS embed.FS
//go:embed *.sql
var migrations embed.FS
//go:embed templates/*.html templates/*.css
var assetsFS embed.FS
Multiple directives can target the same variable:
//go:embed index.json
//go:embed *.gotmpl
//go:embed *.json
var templatesFS embed.FS
HTTP file server
Serve embedded files over HTTP:
import (
"embed"
"io/fs"
"net/http"
)
//go:embed static/*
var staticFS embed.FS
func main() {
// Strip "static/" prefix so /app.css serves static/app.css
stripped, _ := fs.Sub(staticFS, "static")
http.Handle("/", http.FileServer(http.FS(stripped)))
http.ListenAndServe(":8080", nil)
}
Lazy loading
Combine with sync.OnceValues (Go 1.21+) to parse embedded files once:
//go:embed config.json
var configBytes []byte
var configOnce = sync.OnceValues(func() (*Config, error) {
var cfg Config
if err := json.Unmarshal(configBytes, &cfg); err != nil {
return nil, err
}
return &cfg, nil
})
func GetConfig() (*Config, error) {
return configOnce()
}
The function runs once on first call; subsequent calls return cached results.
Template parsing
Parse embedded templates at startup:
//go:embed templates/*.html
var templatesFS embed.FS
var templates = template.Must(
template.ParseFS(templatesFS, "templates/*.html"),
)
func render(w http.ResponseWriter, name string, data any) {
templates.ExecuteTemplate(w, name, data)
}
When to use
- CLI tools that need bundled templates, configs, or assets
- Web servers with static files (HTML, CSS, JS, images)
- Database migrations shipped with the binary
- Any deployment where fewer moving parts is valuable
When not to use
- Files that change frequently without code changes
- Very large assets (increases binary size and memory usage)
- Content that users should be able to modify at runtime