Live Reloading Your Golang Apps Made Easy – Here’s How

As a Go developer, the inability to live reload your applications can be frustrating. Unlike many other languages and frameworks, we have to manually rebuild and rerun to see our changes. This undoubtedly has an impact on productivity and needless to say is a tedious process. However, fear not! In this blog post, I will clear the air on live reloading in Go and demonstrate how it can be achieved with CompileDaemon and Docker Compose.

Table Of Contents

What Is Live Reloading?

Live reloading is the process of automatically rebuilding and restarting the entire application after a change to the source code. Live reloading and hot reloading are often used interchangeably and although they share some similarities, they are not the same.

Hot reloading only updates the modified parts of the application. It injects the updated code directly into the running application, preserving the application state and avoiding the need for a complete rebuild or restart.

Go is a compiled language, meaning the code needs to be compiled into machine code before it can be executed. This compilation process enables Go to achieve impressive speed and efficiency. However, this also increases the complexity of supporting hot reloading. At the time of this post, Go does not support any prospect of hot reloading, but we can still achieve live reloading.

What Is CompileDaemon?

CompileDaemon is a small utility which monitors your Go source code and automatically rebuilds your application whenever a change is detected. If you would like to see all the features of CompileDaemon, check the documentation.

Docker allows us to encapsulate applications and their dependencies into a container. This ensures consistent behaviour across different machines. Luckily for us, CompileDaemon and Docker make a great pairing.

We can containerise the application in Docker Compose, mount the source code to a volume and CompileDaemon can monitor the volume for changes. This helps us achieve a highly efficient and convenient live reloading setup.

Example Implementation

In this example, we will construct a simple Gin API which will live reload within a Docker container using CompileDaemon and Docker Compose. Before we begin, ensure you have Docker installed and running.

Create a new directory called live-reloading-example and initialise a new go module.

go mod init
Bash

Add Gin as a dependency.

go get -u github.com/gin-gonic/gin
Bash

Creating An API With Gin

Create a main.go file which will start a Gin server containing a /hello endpoint which returns a hardcoded JSON response.

package main

import (
    "net/http"

    "github.com/gin-gonic/gin"
)

func main() {
    r := gin.Default()
    
    r.GET("/hello", func(c *gin.Context) {
        c.JSON(http.StatusOK, gin.H{"message": "hello"})
    })

    r.Run(":8000")
}
Go

Build and run the application.

go build && ./live-reloading-example
Bash

Open your browser and navigate to the URL below.

http://localhost:8000/hello

Ensure you are getting the expected response.

{"message": "hello"}
JSON

Creating The Dockerfile

Let’s put our app in a container by creating a new Dockerfile.

# Go Version
FROM golang:1.21-rc-alpine3.17

# Environment variables which CompileDaemon requires to run
ENV PROJECT_DIR=/app \
    GO111MODULE=on \
    CGO_ENABLED=0

# Basic setup of the container
RUN mkdir /app
COPY .. /app
WORKDIR /app

# Get CompileDaemon
RUN go get github.com/githubnemo/CompileDaemon
RUN go install github.com/githubnemo/CompileDaemon

# The build flag sets how to build after a change has been detected in the source code
# The command flag sets how to run the app after it has been built
ENTRYPOINT CompileDaemon -build="go build -o api" -command="./api"

To check everything is working so far, we will build a Docker image from the Dockerfile.

docker build -t live-reloading-example . 
Bash

Run the Docker image.

docker run -p 8000:8000 live-reloading-example
Bash

Check in the browser that you get the same response as before.

You will notice that the application will not live reload yet. This is because a Dockerfile is not supposed to be dynamic. They are used to build images which are a static snapshot of an application and its dependencies. To achieve live reloading we need to leverage Docker Compose.

Finishing Up With Docker Compose

Create a compose.yaml file in the project root with the following code.

version: '3.8'
name: live-reload-example
services:
  api:
    container_name: api
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - 8000:8000
    volumes:
      - ./:/app
YAML

You may have noticed that we are mounting our app folder to a volume. CompileDaemon will monitor this volume for changes and trigger the build and run commands which were set in the Dockerfile.

Start Docker Compose.

docker-compose up
Bash

Open the browser and make sure that you still get the message.

{"message": "hello"}
JSON

In the main.go file, change the message from hello to goodbye and save the file. You will see the project rebuild in the logs. Refresh the browser and you will see the message has changed to goodbye.

With this setup in place, you can now make changes to your source code and CompileDaemon will automatically rebuild and restart your application.

If you would like to download the example code, it is available on our GitHub.

Conclusion

In conclusion, Go may not provide native support for live reloading, but that doesn’t mean we don’t have an effective solution. By using tools like CompileDaemon and Docker Compose, we can achieve live reloading and eliminate those annoying manual rebuilds.

Although live reloading isn’t useful in every scenario, you should make it an option in your Makefile as it can increase productivity when developing new features.

If you have any questions or comments, please leave them below. Also, don’t forget to subscribe to our newsletter to receive more informative posts like this directly to your inbox.

If you found this article helpful, please share it with your friends and colleagues.

Thank you for reading!

Leave a Reply

Your email address will not be published. Required fields are marked *