Go embed: Embed your HTML frontend in Golang

Table of contents

Parsing HTML files into Go can be easy using the "html/template" package until the main file is moved somewhere else or errors arise because you did not use containers (or docker) when hosting the application. In Go 1.16, a package called embed was introduced and it serves many purposes but mainly: embedding "anything" - strings, bytes, even files. This article explains how to use the embed package to insert HTML files into your golang application, build the golang app into an executable(.exe) file, and run that .exe file anywhere on your system without "HTML file not found" errors popping up.
Pre-requisites:

  • Golang installed on your system
  • basic knowledge of Golang

    The finished project can be found here: finished project
    Setup the project:
  • create a folder in your $GOPATH and name it go-embed
  • cd into go-embed and run: go mod init go-embed`
  • create the main.go inside the go-embed folder
  • create a folder templates, cd into templates and create the index.html file
    go-embed-1.png

Updating the files:
For the index.html, we display a simple message.
index.html

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Go Embed</title>
</head>

<body>
  <h4>Go Embed: Embed HTML in Go</h4>
</body>

</html>


For the main.go file, we serve the HTML. I am using the default "net/http" package but you can use any package of your choice e.g. the "gorilla/mux" package.
main.go:

package main

import (
    "fmt"
    "html/template"
    "log"
    "net/http"
)

func indexHandler(w http.ResponseWriter, r *http.Request) {
    tmpl, err := template.ParseFiles("templates/index.html") // serving the index.html file
    if err != nil {
        log.Fatal(err)
    }
    tmpl.Execute(w, nil)
}

func main() {
    http.HandleFunc("/", indexHandler)

    fmt.Println("Server starting on port 8000!")
    err := http.ListenAndServe(":8000", nil)
    if err != nil {
        log.Fatal(err)
    }
}


Run the application: go run main.go
go-embed-2.png Open our app on the browser:

go-embed-3.png

Using the embed package:
In this section, we would embed the HTML file(index.html) in the Go binary which allows us to send the binary file anywhere and run that file without displaying any error.
Updating main.go:

package main

import (
    "embed"
    "fmt"
    "html/template"
    "log"
    "net/http"
)

//go:embed templates
var tplFolder embed.FS // embeds the templates folder into variable tplFolder

func indexHandler(w http.ResponseWriter, r *http.Request) {
    tmpl, err := template.ParseFS(tplFolder, "templates/index.html")
    if err != nil {
        log.Fatal(err)
    }
    println("Embedded the index.html file")
    tmpl.Execute(w, nil)
}

func main() {
    http.HandleFunc("/", indexHandler)

    fmt.Println("Server starting on port 8000!")
    err := http.ListenAndServe(":8000", nil)
    if err != nil {
        log.Fatal(err)
    }
}


Run the application: go run main.go
go-embed-4.png

Refresh the browser page:
go-embed-5.png Check the running application server:
go-embed-6.png We do not have any error, instead we have successfully embedded index.html.

Building the file:
First we stop the app server running.
Build the file by running: go build
We have a binary application:
go-embed-7.png Move the binary file somewhere else and run it: ./go-embed for Linux/Mac or go-embed for Windows.
go-embed-8.png

Refresh the browser page:
go-embed-9.png Our app server:
go-embed-10.png Where can this embed feature be applied?
An example: Github
Here, I embedded all the HTML files which allow me to perform the authentication (registration or login) anywhere my application is even though the HTML files are not present. This makes hosting the application on Heroku or any hosting platform easier without getting file errors.

2
Subscribe to my newsletter

Read articles from Madukoma Blessed directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Madukoma Blessed
Madukoma Blessed

A software engineer with 3+ years of experience, tasked with demystifying the amazing world of scalable, performant systems by designing, developing and maintaining high-quality, user-friendly services. Having worked on various projects ranging from startups to big tech enterprises, my interests lie in areas including data, software systems, technology, finance, customers and organizational success. As a skilled communicator and innovative engineer with an eye for detail, I excel in fast-paced environments. I find joy in collaborating with diverse teams of designers, engineers, and product managers, crafting tailored solutions that perfectly fit an organization's requirements.