Embedding Files & Build Tags

The //go:embed directive bakes files and directories straight into your compiled binary so you can ship a single self-contained executable, while build tags ( //go:build ) decide which source files are compiled for which platform.

Learn Embedding Files & Build Tags in our free Go course — an interactive lesson with runnable examples, a practice exercise and a quick reference.

Part of the free Go course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.

What You'll Learn in This Lesson

1️⃣ Embedding with //go:embed

Put //go:embed <path> on the line directly above a package-level variable and import embed . A string or []byte variable receives a single file; an embed.FS receives whole directories as an in-memory filesystem you can ReadFile and fs.WalkDir . This example assumes a project with version.txt and a static/ folder next to it.

2️⃣ Serving an embedded site

Because embed.FS implements the standard fs.FS interface, you can serve it directly: wrap it with http.FS and hand it to http.FileServer . Your entire front-end ships inside one binary. We exercise it with httptest so you can see a real response.

3️⃣ Build constraints ( //go:build )

A //go:build line at the top of a file (above package , followed by a blank line) controls when that file is compiled. Split a platform-specific symbol across files: the toolchain includes exactly the ones whose constraints match the target GOOS . Here three files define a single program; on Linux only greet_linux.go is compiled.

🎯 Your Turn

Embed a single file into a string and print it. Fill in the two blanks marked ___ , create banner.txt next to the file, then run it.

❌ Blank line between //go:embed and the var — "directive must be followed by a Go variable".

❌ Embedding without import "embed" — won't compile.

✅ Import it (use _ "embed" for the string/[]byte forms).

❌ Embed path points outside the package directory (e.g. ../assets ) — not allowed.

✅ Embed only files at or below the package's own directory.

❌ //go:build not at the top (or no blank line after it) — the constraint is ignored.

✅ First non-comment lines of the file, then a blank line, then package .

string (or []byte ) for a single file; reach for embed.FS when bundling multiple files or whole directories.

Skipped entirely — it's not compiled into a Windows build, so a matching //go:build !linux file supplies the symbol instead.

Add the //go:embed templates directive over the embed.FS , then ReadFile both templates and print them.

Practice quiz

What does the //go:embed directive do?

  • Imports a package
  • Runs code at startup
  • Copies a file or directory into the binary at build time
  • Downloads files at runtime

Answer: Copies a file or directory into the binary at build time. //go:embed bakes the contents of a file or directory into the compiled binary at build time.

Where must //go:embed be placed relative to the variable?

  • On the line directly above the variable, with no blank line
  • Anywhere in the file
  • Inside main
  • At the top of the file

Answer: On the line directly above the variable, with no blank line. The directive must sit on the line directly above the package-level variable, with no blank line between.

Which import is required to use //go:embed?

  • os
  • io/fs
  • bytes
  • embed

Answer: embed. You must import "embed" (a blank import _ "embed" works for the string/[]byte forms).

Which variable type should you use to embed a SINGLE file's text?

  • embed.FS

A string or []byte receives a single file; use embed.FS for multiple files or directories.

What type bundles a whole directory tree of files?

  • embed.FS

Answer: embed.FS. embed.FS gives you an in-memory filesystem you can ReadFile, Open, and fs.WalkDir over.

How do you serve an embed.FS over HTTP?

  • http.ServeFile(fs)
  • fs.Serve()
  • http.FileServer(http.FS(staticFiles))
  • embed.Serve(fs)

Answer: http.FileServer(http.FS(staticFiles)). Wrap the embed.FS with http.FS to get an http.FileSystem, then pass it to http.FileServer.

What does a //go:build line at the top of a file control?

  • The package name
  • When (on which platform) that file is compiled
  • Runtime behavior
  • The import order

Answer: When (on which platform) that file is compiled. A //go:build constraint tells the toolchain when to include the file, e.g. only on a given GOOS.

A file with //go:build linux is compiled into a Windows build...

  • Always
  • Only with a flag
  • Only if it has no errors
  • Never — it is skipped

Answer: Never — it is skipped. On Windows the constraint isn't satisfied, so the file is skipped entirely; a //go:build !linux file supplies the symbol.

Can you embed a file outside the package directory, like ../assets?

  • Yes
  • No — only files at or below the package directory
  • Only with embed.FS
  • Only on Linux

Answer: No — only files at or below the package directory. Embed paths must be at or below the package's own directory; pointing outside it (e.g. ../assets) is not allowed.

Why must a //go:build line be followed by a blank line before package?

  • For readability only
  • To separate imports
  • Otherwise the constraint is treated as an ordinary comment and ignored
  • It is not required

Answer: Otherwise the constraint is treated as an ordinary comment and ignored. The constraint must be at the top followed by a blank line before package, or it is ignored as a regular comment.