Embedding static files in a go binary using go embed
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
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/
The final result is a single web server binary ready for distribution. For more information check out the official embed documentation. Happy embedding.
The source code for the server is available at