Golang Local Development with Live Reloading using Air and Docker Compose Learn how to set up a Golang development environment with live reloading using Air and Docker Compose, making your development process faster and more efficient.
August 12, 2024
Back to Blog list
Mention the tools that need to be installed before proceeding:
Golang (at least version 1.18+)
Docker and Docker Compose
air (installation instructions will be provided later)
Create a new directory for your project and navigate into it:
mkdir golang-docker-air
cd golang-docker-air
Initialize a new Go module:
go mod init github.com / yourusername / golang - docker - air
Create a simple main.go
file:
package main
import " fmt "
func main () {
fmt. Println ( "Hello, World!" )
}
Use the following command to install Air for live reloading. This instruction works fine for Unix systems, you can look for more informations here on Air documentation.
curl -sSfL https://raw.githubusercontent.com/air-verse/air/master/install.sh | sh -s
Run air init
, and will be created a file on root of your project called .air.toml
.
Now update cmd value property from .air.toml to:
Before:
cmd = "go build -o ./tmp/main ."
After:
cmd = "go build -o ./tmp/main ./cmd/app/main.go"
Now, let's create a directory cmd/app
on the root of the project, and move our main.go
file to this new directory.
Create a Dockerfile to define the Go environment:
FROM golang:1.22.5
# Set the working directory
WORKDIR /app
# Install air for hot reloading
RUN go install github.com/air-verse/air@latest
# Copy go.mod and go.sum files
COPY go.mod go.sum ./
RUN go mod tidy && go mod verify
# Copy the rest of the application code
COPY . .
# Install air configuration
COPY .air.toml .air.toml
# Command to run air for hot reloading
CMD [ "air" ]
Create a docker-compose.yaml file to define the services:
services:
api:
build: .
env_file:
- .env
ports:
- "3000:3000"
volumes:
- .:/app
- /app/tmp
networks:
- backend
volumes:
api_volume:
networks:
backend:
driver: bridge
Now, let's add chi
package to make the test, just to try to have something close to a real scenario.
Run the following command below to install chi
package to our project. Link from chi
repository is here .
go get - u github.com /go- chi / chi / v5
Now, let's just add the following code to our main.go
file (cmd/app/main.go ):
package main
import (
" fmt "
" log "
" net/http "
" github.com/go-chi/chi/v5 "
)
func main () {
r := chi. NewRouter ()
fmt. Println ( "Server starting at http://localhost:3000" )
err := http. ListenAndServe ( ":3000" , r)
if err != nil {
log. Fatalf ( "Server failed: %v " , err)
}
}
Now, let's just run the following command on our terminal:
docker-compose up
And we'll have something like this:
[+] Building 0.0s ( 0/0 ) docker:desktop-linux
[+] Running 2/2
✔ Network golang-docker-air_backend Created 0.0s
✔ Container golang-docker-air-api-1 Created 0.1s
Attaching to golang-docker-air-api-1
golang-docker-air-api-1 |
golang-docker-air-api-1 | __ _ ___
golang-docker-air-api-1 | / / \ | | | | _ )
golang-docker-air-api-1 | /_/--\ | _ | | _ | \_ v1.52.3, built with Go go1.22.5
golang-docker-air-api-1 |
golang-docker-air-api-1 | watching .
golang-docker-air-api-1 | watching cmd
golang-docker-air-api-1 | watching cmd/app
golang-docker-air-api-1 | ! exclude tmp
golang-docker-air-api-1 | building...
golang-docker-air-api-1 | go: downloading github.com/go-chi/chi/v5 v5.1.0
golang-docker-air-api-1 | running...
golang-docker-air-api-1 | Server starting at http://localhost:3000
Now let's add a 🚀 at the and of our log message, just to show that our container will be reloaded:
package main
import (
" fmt "
" log "
" net/http "
" github.com/go-chi/chi/v5 "
)
func main () {
r := chi. NewRouter ()
fmt. Println ( "Server starting at http://localhost:3000 🚀" )
err := http. ListenAndServe ( ":3000" , r)
if err != nil {
log. Fatalf ( "Server failed: %v " , err)
}
}
This is our terminal:
[+] Building 0.0s ( 0/0 ) docker:desktop-linux
[+] Running 2/2
✔ Network golang-docker-air_backend Created 0.0s
✔ Container golang-docker-air-api-1 Created 0.1s
Attaching to golang-docker-air-api-1
golang-docker-air-api-1 |
golang-docker-air-api-1 | __ _ ___
golang-docker-air-api-1 | / / \ | | | | _ )
golang-docker-air-api-1 | /_/--\ | _ | | _ | \_ v1.52.3, built with Go go1.22.5
golang-docker-air-api-1 |
golang-docker-air-api-1 | watching .
golang-docker-air-api-1 | watching cmd
golang-docker-air-api-1 | watching cmd/app
golang-docker-air-api-1 | ! exclude tmp
golang-docker-air-api-1 | building...
golang-docker-air-api-1 | go: downloading github.com/go-chi/chi/v5 v5.1.0
golang-docker-air-api-1 | running...
golang-docker-air-api-1 | Server starting at http://localhost:3000
golang-docker-air-api-1 | cmd/app/main.go has changed
golang-docker-air-api-1 | building...
golang-docker-air-api-1 | running...
golang-docker-air-api-1 | Server starting at http://localhost:3000 🚀
By following the steps in this guide, you've successfully set up a Golang development environment with live reloading using Air and Docker Compose. This setup streamlines your workflow, allowing you to focus on writing and testing your code without the need to restart your application manually.
With the combination of Docker Compose and Air, you now have a flexible, containerized development environment that can be easily scaled or adapted to fit more complex applications. Whether you're building a simple API or a larger microservices architecture, this approach ensures your development process remains efficient and productive.
Feel free to expand on this foundation by integrating other tools or services, exploring different Go packages, or customizing your Docker setup. The possibilities are vast, and this setup is just the beginning of what you can achieve with Go and Docker.
Happy coding! 🚀