Live Reloading in Golang using Air

Live reloading changes to our codebase is one of the core tenants of a great developer experience. When we make changes to our codebase, we want to be able to get feedback on the results as soon as possible. Live reloading is the process of watching codebase changes and automatically rebuilding the application with the changes integrated. It can be very frustrating if you have to do this manually: save changes, stop the server, rebuild and then start the server on every change you make.

Having worked with NodeJS based frameworks and frontend frameworks such as Angular and React, most (if not all) come with live reloading built-in. Some frameworks such as Flutter take this a little further with stateful hot reloading, which I won't go into details about.

Having switched to using Golang recently, I realized I needed to solve this problem. Lucky for me, there are a few great options out there to enable this behavior. One of them is the Air (github.com/cosmtrek/air) - a live reloading tool for Golang apps.

Installing Air

First, we are going to install air. There are a number of ways to install air, but the way I did it was using go install as I had Golang already installed:

go install github.com/cosmtrek/air@latest

There are a number of other installation options that you can find here.

Configuring Air

Next, we need to configure Air for our Golang project. You can do that by running the following command:

air init

This will create a air.toml file that will contain the default configurations for Air. Here is an example of what that looks like:

root = "."
testdata_dir = "testdata"
tmp_dir = "tmp"

[build]
  bin = "./tmp/main"
  cmd = "go build -o ./tmp/main ."
  delay = 1000
  exclude_dir = ["assets", "tmp", "vendor", "testdata"]
  exclude_file = []
  exclude_regex = ["_test.go"]
  exclude_unchanged = false
  follow_symlink = false
  full_bin = ""
  include_dir = []
  include_ext = ["go", "tpl", "tmpl", "html"]
  kill_delay = "0s"
  log = "build-errors.log"
  send_interrupt = false
  stop_on_error = true

[color]
  app = ""
  build = "yellow"
  main = "magenta"
  runner = "green"
  watcher = "cyan"

[log]
  time = false

[misc]
  clean_on_exit = false

[screen]
  clear_on_rebuild = false

Next, let me highlight a few notable configurations you might care about and might want to update for your project.

Under build in the air.toml; you might want to change the cmd property. If the entry of your golang application is in a different directory, say server, you can change the property to something like this:

cmd = "go build -o ./tmp/main ./server/main.go"

Another set of config properties that you might want to pay attention to are the include_dir, include_ext, exclude_dir and exclude_file entries. The include_dir and include_ext tell Air which dir and extensions to watch for changes when live reloading, while the exclude_dir and exclude_file tell air which directories, extensions, and files not to listen to changes from.

There is also the exclude_regex property that allows you to ignore files matching a certain pattern, i.e. test files as it does by default. These configs allow you to configure Air based on your app structure.

For more information about Air configurations, please refer to the example file here.

Running your App

Finally, the only part that is remaining is running our Golang application using Air. You can do this by running the air command:

air

After that, make changes to your project and watch air live-reload your Go application.

Conclusion

In this article, we learned how we can use Air to live-reload our go applications as we make changes to our codebase. We learned how we can initialize, the configuration we might want to change, and how to start our application afterward.

To continue learning more about Air, visit the Github repository here.