Embedding files natively in Go 1.16

Alberto de Murga
3 min readDec 25, 2020
Gophers with a wrench by Renee French

One of the most commonly noted upsides of Go is the compilation to a single binary. This makes deployments and dependency requirements easier to handle compared to other languages that require to install in the target system the individual dependencies which can potentially conflict with other software running or require to install duplicated packages.

However, sometimes Go programs not always can be reduced to a single file. Assets like templates or images are not included as part of the binary and they need to manage and deployed independently. Although this has its benefits, like customising templates without having to recompile the whole program, it loses the benefits of a single unit when you do not want or do not expect to make a change in the assets, like with games.

Traditionally, we have relied on third-party packages like go-bindata or statik to embed static assets in Go binaries. These tools essentially require to run a command against the assets we want to embed to create a Go file which contains a binary representation of them. Later, you import this generated file in your code and you access the files using some key based on the path or a virtual file system.

These solutions have some issues in terms of development experience. They require an extra step to add/update assets every time they change and having the tool available in each environment in some concrete version. It is also an external dependency, which might be complicated to adopt in certain corporate environments. Also, to keep the component “go-getable”, you need to commit the generated files, which is not ideal either.

In version 1.16 (not available yet as of December 2020), the Go team has introduced a new package named embed which solves these trade-offs by embedding the files during the building of the binary. Hence, we don't need to run additional commands before running go build or to track generated files. The go build system will recognise the directives and populate the variables with the matching files.

How it works

General conditions

  1. If any patterns are invalid or have invalid matches, the build will fail.
  2. The directive must immediately precede a line containing the declaration of…
Alberto de Murga

Software engineer at @bookingcom. I like to make things, and write about what I learn. I am interested in Linux, git, JavaScript and Go, in no particular order.