Stage 1 · Code
Standard Library Toolkit
Pack Files Into the Binary
Sometimes the safest way to ship a file is to stop shipping it separately. Go's `embed` package lets you bundle templates, config, and other static assets directly into the compiled program.
Why Embedding Is Useful
A binary that expects extra files beside it can fail for dull reasons: the template folder was not copied, the config path changed, or the working directory is not what the developer assumed. Those bugs are frustrating because the code itself may be fine. The packaging is what breaks.
Embedding solves that by moving static files inside the compiled binary. Now the executable and the files travel as one unit. That is especially helpful for single-binary deployment and for tools that need a handful of built-in assets every time they start.
The file still exists at development time, but once you build the program its contents are copied into the binary. At runtime, the program reads from its own compiled data instead of reaching back out to the disk copy.
Embedding Single Files
The embed package uses a compiler directive: //go:embed. That comment tells the compiler which file or directory to bundle. You place the directive directly above a variable with one of the supported types.
A string target is convenient for text you want to print or template immediately. A []byte target is convenient when the program needs raw bytes, perhaps to hash them or pass them into another parser.
Embedding Directories
For more than one file, embed.FS is the workhorse. Think of it as a read-only virtual filesystem backed by compiled-in data. The nice part is that many standard library helpers already know how to read from any filesystem-like value, not just the real disk.
Tradeoffs and Choices
Embedding is convenient, but it is not free. The binary grows because the file contents are copied inside it. And because the data is compiled in, updating those files means rebuilding the program.
| Approach | Strength | Cost |
|---|---|---|
| Embedded files | Single-binary deployment, fewer missing-file mistakes, predictable startup assets | Larger binary and no runtime updates without recompiling |
| Read from disk at runtime | Files can be swapped or edited without rebuilding | More moving parts during deployment and more room for path mistakes |
A good rule is to embed static assets that truly belong to the program version itself: default templates, help text, seed config, built-in web assets. If the file is supposed to be changed by operators after deployment, runtime disk access is often the better choice.
If your helper functions accept fs.FS instead of hard-coding os.ReadFile, the same code can read embedded files, real files, or even in-memory test files with almost no changes.
Quiz
Why is embedding useful for deployment?
Practice
Write a function `ReadTextFile(fsys fs.FS, path string) (string, error)` that reads a file from any filesystem implementation and returns its contents as a string.
Summary
//go:embedcopies static files into the compiled binary.- Single files can be embedded into
stringor[]bytevariables. - Whole directories are commonly embedded into
embed.FS. - Embedding reduces runtime file-missing problems and simplifies single-binary deployment.
- The tradeoff is binary size and the need to rebuild when embedded assets change.
Mark this lesson complete to store local progress and unlock a cleaner resume path the next time you visit.