fmt, io, os, bufio, encoding/json, net/http, time, slog, regexp, flag, embed.
embed — Bake Files Into the Binary
go:embed lets you embed files and directories directly into your Go binary at
compile time. No runtime filesystem lookup, no shipping a static/ folder
alongside the executable. One file goes to your server, everything is inside it.
Common uses: HTML templates, SQL migrations, CSS/JS assets, certificate bundles, small datasets.
A single file
package main
import (
_ "embed"
"fmt"
)
//go:embed banner.txt
var banner string
func main() {
fmt.Println(banner)
}
The //go:embed directive must be on the line immediately before a package-level
variable. The variable can be string, []byte, or embed.FS.
A whole directory: embed.FS
Use embed.FS when you want a filesystem-like API over a directory tree:
In a real project:
//go:embed templates/*.html
var templatesFS embed.FS
tmpl := template.Must(template.ParseFS(templatesFS, "templates/*.html"))
Serving embedded static files over HTTP
The net/http and io/fs packages know about embed.FS:
//go:embed static
var staticFS embed.FS
mux := http.NewServeMux()
mux.Handle("/static/", http.FileServer(http.FS(staticFS)))
You ship one binary. No cp -r static/ /opt/app/static/ in your deploy script.
Glob patterns
The //go:embed directive accepts globs and multiple paths:
//go:embed migrations/*.sql
//go:embed schema.json
var assets embed.FS
But beware: * doesn't cross directories. To embed a tree, use all::
//go:embed all:templates
var templates embed.FS
The all: prefix includes hidden files (_ and .-prefixed) and recursive
contents.
When NOT to embed
- Files users should be able to edit without a rebuild (config, environment-specific values) → keep as separate files.
- Anything secret →
go:embedputs the bytes into the binary in plaintext. Use a secret manager. - Multi-gigabyte assets → keep external.