Golang embed files in binary (with React build example)

Go is known to create statically linked binaries without any runtime dependencies. Static binaries are great for deployment as it needs just one file resulting in less chances of envionment specific issues.

But there is one issue, If you want to embed some static assets(Front-end files, Images etc) There was no native way to do so.

This changes with Go 1.16, Go introduces new embed package to solve this issue.

How to use embed #

There are 3 ways to use embed package.

  1. Get file as string
  2. Get file as byte slice
  3. Get file(s) as embed.FS type

Even though embed package is not referenced in first 2 ways, it need to be imported. It can be imported as import _ "embed"

Get file as string #

package main

import (
	_ "embed"
	"fmt"
)

//go:embed hello.txt
var s string

func main() {
	fmt.Println(s)
}

Get file as []byte #

package main

import (
	_ "embed"
	"fmt"
)

//go:embed hello.txt
var b []byte

func main() {
	fmt.Println(string(b))
}

Get file as embed.FS #

package main

import (
	"embed"
	"fmt"
)

//go:embed hello.txt
var f embed.FS

func main() {
  data, _ := f.ReadFile("hello.txt")
  print(string(data))
}

How to serve front end application using Go embed #

Lets see how we can serve any front end build directory using embed.

Change the filename to a filepath in go:embed comment. Like below

//go:embed client/build
var content embed.FS // build directory holds a client react build

Go 1.16 has also introduced few more changes like http.FS and one more package io/fs to make it easier to work with filesystem.

To convert embed.FS to http.FileSystem, http.FS can be used, So we can do

http.Handle("/",  http.FileServer(http.FS(content)))

But there is an issue, Now we need to access HOST/client/build to access index.html file. We need to serve subdirectory of content, which we can get using

fsys := fs.FS(content)
contentStatic, _ := fs.Sub(fsys, "client/build")

Final Code

package main

import (
	"embed"
	"io/fs"
	"net/http"
)

//go:embed client/build
var content embed.FS

func clientHandler() http.Handler {
	fsys := fs.FS(content)
	contentStatic, _ := fs.Sub(fsys, "client/build")
	return http.FileServer(http.FS(contentStatic))

}
func main() {
	mux := http.NewServeMux()
	mux.Handle("/", clientHandler())
	http.ListenAndServe(":3000", mux)

}

Full code link : https://github.com/akmittal/go-embed


Since you've made it this far, sharing this article on your favorite social media network would be highly appreciated ! For feedback, please ping me on Twitter.

Published