Use go:embed to compile static assets like HTML templates, JSON configs, or binary files directly into your Go binary, eliminating the need for external file dependencies or complex bundling steps. You simply declare an embedded variable with the //go:embed directive pointing to your asset directory or file, then read from that variable at runtime as if it were a file on disk.
For a CLI tool that needs to serve help documentation or configuration templates, you can embed a directory of files and access them via embed.FS. This approach ensures your CLI is truly portable; you can distribute a single executable that contains all necessary resources without worrying about missing files on the target machine.
Here is a practical example of embedding a directory of templates and rendering one:
package main
import (
"embed"
"fmt"
"html/template"
"os"
)
//go:embed templates/*
var templateFS embed.FS
func main() {
// Read the template file from the embedded filesystem
tmplContent, err := templateFS.ReadFile("templates/welcome.html")
if err != nil {
fmt.Fprintf(os.Stderr, "Error reading template: %v\n", err)
os.Exit(1)
}
// Parse and execute the template
tmpl, err := template.New("welcome").Parse(string(tmplContent))
if err != nil {
fmt.Fprintf(os.Stderr, "Error parsing template: %v\n", err)
os.Exit(1)
}
data := map[string]string{
"AppName": "MyCLI",
"Version": "1.0.0",
}
if err := tmpl.Execute(os.Stdout, data); err != nil {
fmt.Fprintf(os.Stderr, "Error executing template: %v\n", err)
os.Exit(1)
}
}
In this setup, the templates directory must exist in your project structure relative to the Go file containing the directive. The embed.FS type implements the fs.FS interface, allowing you to use standard library functions like ReadFile, Open, or Glob to interact with the assets. If you only need a single file, you can embed it directly into a string or byte slice using //go:embed filename.txt and var content string or var data []byte.
When building your CLI, the assets are automatically included in the final binary. You do not need to copy files to the deployment directory or configure a separate asset server. This is particularly useful for CLIs that generate reports, display formatted help screens, or require default configuration files that users can override but don't strictly need to provide manually. Just ensure your go.mod file is in the same directory as your source code or that the relative paths in the //go:embed directive correctly resolve to the assets from the build context.