Learn Go← Dashboard

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:

go playground
Loading...

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:embed puts the bytes into the binary in plaintext. Use a secret manager.
  • Multi-gigabyte assets → keep external.
Why does `//go:embed banner.txt` silently do nothing in some builds?