How does //go:embed work? Show the three target types.
Question 433MediumGo 1.22 to 1.25
//go:embed (Go 1.16) compiles files into the binary at build time. The directive goes immediately above a package-level variable of type string, []byte, or embed.FS. Paths are relative to the source file's directory.
package web
import (
"embed"
"io/fs"
"net/http"
)
//go:embed VERSION
var version string // single file only
//go:embed schema.sql
var schema []byte // single file only
//go:embed static templates/*.tmpl
var assets embed.FS // many files / dirs, read-only fs.FS
func Handler() http.Handler {
sub, err := fs.Sub(assets, "static") // strip "static/" prefix
if err != nil {
panic(err)
}
return http.FileServerFS(sub) // Go 1.22+
}
Key points:
- You must import
embed. Use a blank import_ "embed"when only string or []byte targets are used. embed.FSimplementsfs.FS,fs.ReadDirFSandfs.ReadFileFS, so it works withtemplate.ParseFS,http.FSand similar.- It is read-only and safe for concurrent use.
- No copy is made at startup. A
stringtarget points at read-only data. A[]bytetarget points at writable data, so mutating it is allowed, but every user of that variable sees the change (copy it if you need a pristine version).embed.FScontents cannot be modified.
This is the typical interview answer for "ship a single binary with a SPA, migrations or templates".
More on Modules, Packages & Tooling
- Q431What does go vet catch? What does it report for the code below?
- Q432How do staticcheck and golangci-lint differ from go vet? How would you set up linting for a team?
- Q434What are the gotchas of go:embed patterns? Why is my .env or _redirects file missing?
- Q435What does this print? Explain Go's package initialization order.
- Q436Go forbids import cycles. How do you detect and break them?
- Q437A vulnerable dependency shows up in your build. How do you find out why it's there and upgrade it safely?