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

When not to use

← All articles