Embedding static files in a go binary using go embed

Harsimran Singh Maan
The Startup
Published in
3 min readDec 18, 2020

--

Starting with Golang 1.16, file embedding is supported in Go without the need of an external package. I have been using packages like pkgr and packr to make it easier to embed static files in go binaries. We’ll explore the usage of the new //go:embed directive in this post.

Why do we need static file embedding?

There would be cases when we’d want to embed static files in the binary. While it is possible to build a binary that reads static files off the disk, it is often cumbersome to ship it to end users as the static files have to be located at a certain place on user’s device or the location has to be configurable. On top of that, the user must remember to update all the files/config refs when upgrading or moving the binary to a new location.

Here are some common use cases where static file embedding is often used:

Go templates: The template files need to be available to the binary. This is a fairly common use case for web server binaries or CLI applications offering an init command which creates a sample project. In absence of embedding, the templates are often inlined in the code. eg: See qbec init or the source.

Static web servers: Sometimes static files like an index.html or other HTML, JavaScript and CSS files need to be shipped with a golang server binary so that the user can run the server and serve these files. eg: Static file embedding in a web server

Database migrations: Another place where embedded files can be used is to ship database migration scripts with the binary. eg: Database migration files

Using the go embed directive

The first thing you need to use the embed directive is to make sure that you are using at-least golang 1.16. For older versions of Go, consider using pkgr.

We’ll write an application that runs a web app which echoes the url back in a webpage (Fancy!! isn’t it?)

The program reads the web page title from a static title.txt file, serves static files (css/main.css) over the /static/ route and uses a go template index.html.tmpl to render all routes over HTTP port 3000. All static files and templates are embedded in the binary using the new embed directive.

Project structure:
.
├── go.mod
├── main.go
├── static
│ └── css
│ └── main.css
├── templates
│ └── index.html.tmpl
└── title.txt

Example web server with go embed
Web page template: index.html.tmpl

Let’s build and deploy the web server.

$ go version
go version go1.16 darwin/arm64
$ go build . # Build the binary$ cp ./go-embed /tmp/ # copy to temp directory. This would help validate that static files are actually embedded$ cd /tmp && ./go-embed # Run the server2020/12/18 12:21:15 Listening on :3000...
2020/12/18 12:21:23 Serving request for path /some-path-with-css-applied
2020/12/18 12:21:23 Serving request for path /favicon.ico
2020/12/18 12:21:24 Serving request for path /some-path-with-css-applied
2020/12/18 12:21:24 Serving request for path /favicon.ico
2020/12/18 12:21:25 Serving request for path /some-path-with-css-applied
2020/12/18 12:21:25 Serving request for path /favicon.ico

Browse to http://localhost:3000/

Web server serving content embedded by go embed

The final result is a single web server binary ready for distribution. For more information check out the official embed documentation. Happy embedding.

Image Credits: https://gopherize.me/gopher/56d6068d1995da6db9297b5d8b27add7f523ee2f

The source code for the server is available at

--

--