Skip to main content
The //go:embed directive is a compiler directive that allows programs to include arbitrary files and folders in the Go binary at build time. This is useful for bundling static assets, configuration files, templates, and other resources directly into your executable.

What is go:embed?

//go:embed embeds the contents of files into variables at compile time, making them part of your binary. The files become available without needing to distribute them separately.

Benefits

  • Single binary deployment (no external file dependencies)
  • Guaranteed file availability at runtime
  • Simplified distribution and deployment
  • Version-locked assets (files can’t change after build)

Basic Usage

First, import the embed package:
package main

import (
	"embed"
)
If you don’t use any exported identifiers from the embed package, you can do a blank import: import _ "embed"

Embedding into String

Embed a file’s contents into a string variable:
//go:embed folder/single_file.txt
var fileString string

func main() {
	print(fileString)
}
The //go:embed directive must be placed immediately before the variable declaration with no blank lines in between.

Embedding into Byte Slice

Embed a file’s contents into a byte slice:
//go:embed folder/single_file.txt
var fileByte []byte

func main() {
	print(string(fileByte))
}

Embedding Multiple Files

Use embed.FS to embed multiple files or folders:
import "embed"

//go:embed folder/single_file.txt
//go:embed folder/*.hash
var folder embed.FS

func main() {
	// Read files from embedded filesystem
	content1, _ := folder.ReadFile("folder/file1.hash")
	print(string(content1))

	content2, _ := folder.ReadFile("folder/file2.hash")
	print(string(content2))
}
embed.FS implements a simple virtual file system that provides methods like ReadFile, ReadDir, and Open.

Path Rules

Relative Paths

// Paths are relative to the directory containing the Go source file
//go:embed config.json          // File in same directory
//go:embed assets/logo.png      // File in subdirectory
//go:embed ../shared/data.txt   // File in parent directory
Paths must be relative to the directory containing the Go source file. Absolute paths are not allowed.

Wildcards

// Embed all .txt files in a directory
//go:embed templates/*.txt
var templates embed.FS

// Embed all files recursively
//go:embed static/*
var static embed.FS

Complete Example

package main

import (
	"embed"
)

// Embed single file as string
//go:embed folder/single_file.txt
var fileString string

// Embed single file as bytes
//go:embed folder/single_file.txt
var fileByte []byte

// Embed multiple files and folders
//go:embed folder/single_file.txt
//go:embed folder/*.hash
var folder embed.FS

func main() {
	// Print string content
	print(fileString)
	
	// Print byte content
	print(string(fileByte))

	// Read from embedded filesystem
	content1, _ := folder.ReadFile("folder/file1.hash")
	print(string(content1))

	content2, _ := folder.ReadFile("folder/file2.hash")
	print(string(content2))
}

Working with embed.FS

Reading Files

//go:embed static/*
var static embed.FS

// Read file contents
content, err := static.ReadFile("static/index.html")
if err != nil {
	log.Fatal(err)
}

Opening Files

// Open file for reading
f, err := static.Open("static/data.json")
if err != nil {
	log.Fatal(err)
}
defer f.Close()

// Read with bufio or io functions
scanner := bufio.NewScanner(f)

Reading Directories

// List directory contents
entries, err := static.ReadDir("static")
if err != nil {
	log.Fatal(err)
}

for _, entry := range entries {
	fmt.Println(entry.Name(), entry.IsDir())
}

Common Use Cases

import (
    "embed"
    "html/template"
)

//go:embed templates/*
var templateFS embed.FS

func main() {
    tmpl := template.Must(template.ParseFS(templateFS, "templates/*.html"))
    tmpl.Execute(w, data)
}

Embedding Patterns

Single File

Embed individual files as strings or byte slices

Directory

Embed entire directories with wildcards

Multiple Patterns

Combine multiple embed directives for one variable

Filtered Content

Use wildcards to embed only specific file types

Restrictions and Limitations

Files and directories starting with . or _ are excluded. Use the all: prefix to include them:
//go:embed all:static
var static embed.FS
//go:embed can only be used with package-level variables, not local variables inside functions.
Only valid with types: string, []byte, or embed.FS.
All embedded paths must exist when the code is built. Missing files cause build errors.
Embedded files increase binary size. Consider whether to embed large files or load them at runtime.

Best Practices

When embedding more than one file, use embed.FS instead of multiple string/byte variables.
Keep embedded files in dedicated directories like assets/, static/, or templates/.
Always handle errors when reading from embed.FS, even though files are guaranteed to exist:
content, err := fs.ReadFile("file.txt")
if err != nil {
    log.Fatal(err)  // Should never happen, but handle it
}
Add comments explaining what files are embedded and why:
// Embed all HTML templates for the web interface
//go:embed templates/*.html
var templates embed.FS
Use build tags to embed different files for different environments:
//go:build prod
//go:embed config.prod.json
var config []byte

HTTP File Server Example

package main

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

// Embed entire static directory
//go:embed static/*
var staticFiles embed.FS

func main() {
	// Create sub-filesystem removing "static" prefix
	staticFS, err := fs.Sub(staticFiles, "static")
	if err != nil {
		log.Fatal(err)
	}

	// Serve embedded files
	http.Handle("/", http.FileServer(http.FS(staticFS)))
	
	log.Println("Server starting on :8080")
	log.Fatal(http.ListenAndServe(":8080", nil))
}

Reading More

For more details about the embed directive, see the official documentation:

Reading Files

Learn about reading files at runtime

File Paths

Working with file paths in Go

Build docs developers (and LLMs) love