Go cookbook · Beginner

Embed static files and templates in the binary

Deployments break because templates or assets aren't copied next to the binary.

Create a free account to save this page, take notes and track your progress. Sign in

Approach

Use //go:embed to compile files into the binary, serve them with http.FileServerFS, and parse templates from the embedded filesystem.

Solution

package main

import (
	"embed"
	"html/template"
	"io/fs"
	"log"
	"net/http"
)

//go:embed static templates
var content embed.FS

func main() {
	static, err := fs.Sub(content, "static")
	if err != nil {
		log.Fatal(err)
	}
	pages := template.Must(template.ParseFS(content, "templates/*.html"))

	mux := http.NewServeMux()
	mux.Handle("GET /static/", http.StripPrefix("/static/", http.FileServerFS(static)))
	mux.HandleFunc("GET /{$}", func(w http.ResponseWriter, r *http.Request) {
		if err := pages.ExecuteTemplate(w, "index.html", map[string]string{"Title": "Shop"}); err != nil {
			http.Error(w, "template error", http.StatusInternalServerError)
		}
	})
	log.Fatal(http.ListenAndServe(":8080", mux))
}

Pitfalls

  • Embedding huge assets that bloat the binary; serve them from a CDN.
  • Using text/template for HTML, which doesn't escape output (XSS).
  • Forgetting that //go:embed paths are relative to the package directory and can't use ...

Variations

  • Set cache headers for fingerprinted assets (Cache-Control: public, max-age=31536000, immutable).
  • In development, switch to os.DirFS("static") to see changes without rebuilding.

Further reading: embed package

Reference: https://pkg.go.dev/embed

More Go recipes

Was this page helpful?