The upcoming Golang 1.16 release adds native support for embedding files into your binaries with the new embed package.

Using it is very straightforward and simple.

Let's say we have the following file structure:

$ tree .
.
├── assets
│   ├── hello.txt
│   ├── index.html
│   ├── style.css
│   └── template.html
├── go.mod
├── hello.txt
└── main.go

We can embed the a single file like this:

package main

import (
    _ "embed"
    "fmt"
)

func main() {

    //go:embed "hello.txt"
    var s string
    fmt.Println(s)

}

This will put the content of hello.txt in the string variable called s during compilation. If you prefer the file to be embedded as a byte array, you simply change the data type of your variable:

package main

import (
    _ "embed"
    "fmt"
)

func main() {

    //go:embed "hello.txt"
    var b []byte
    fmt.Println(string(b))

}

You can also embed it using the new FS type so that we can read it as a filesystem. This allows you to embed multiple files or a complete file tree at once:

package main

import (
    "embed"
    "fmt"
)

func main() {

    //go:embed hello.txt
    var f embed.FS
    data, _ := f.ReadFile("hello.txt")
    fmt.Println(string(data))

}

We can also use the filesystem type to render templates:

package main

import (
    "embed"
    "fmt"
    "html/template"
    "log"
    "os"
)

//go:embed assets
var assets embed.FS

func main() {

    tmpl, err := template.ParseFS(assets, "assets/template.html")
    if err != nil {
        log.Fatal(err)
    }

    if err := tmpl.Execute(os.Stdout, map[string]string{
        "title":   "My Title",
        "message": "Hello World",
    }); err != nil {
        log.Fatal(err)
    }

}

One last trick, you can also use it in combination with a webserver:

package main

import (
    "embed"
    "fmt"
    "net/http"
)

//go:embed assets
var assets embed.FS

func main() {

    fmt.Println("http://localhost:8080/assets/index.html")
    fs := http.FileServer(http.FS(assets))
    http.ListenAndServe(":8080", fs)

}

You can read all the details about this in the documentation.

Related Posts

  • Looking up a CNAME in Go
  • Truncating a Unix timestamp to the hour using Go
  • Parsing a key pair from a PEM file in Go
  • Gotcha with defer in Go
  • Pretty-print JSON with Go