State before and after
Before:
You're stuck in the loop of hell - constantly stopping your Go web server, recompiling, and starting it again just to see if your template changes work. It's painful.
After:
Now you've got the good stuff - live reloading that actually works WITH proper debugging. No more compile-restart dance. You can set breakpoints, step through your code like a human being, AND you're still logging the important bits.
Your development flow is smooth. Changes happen instantly. You can actually understand what your code is doing instead of guessing. You've grown as an engineer because you're being mindful about your tooling - and that makes you write better code that has a longer use cycle.
☁️ Air tool
If you want to develop web application that is served with Go you usually (very soon) find out that you do not want to compile your Go code to see the changed templates! This eventually leads you to use live reloading to speed up development.
Go has a popular tool for that called air.
Now this article isn't aimed at how you setup everything from scratch. If you wish for content on that topic because you think it's missing after googling it - comment on this post and I'll mix something up.
Debug
I love developing with debugger. I just can't process everything that is happening... I need to walk through code step by step which helps me understand it more deeply.
Do NOT skip logging tho... I have realised that some developers only program with logging - which leaves loads of logs behind which can be useful while debugging in live application - WHILE the other half only uses debugger and never logs anything due to being able to step into the code.
Use both!
I have improved as an engineer due to being mindful about these pillars.
Debug setup with Air
Delve is my go-to debugger for Go - so you need to have it installed.
Air (obviously) is also required for this to work.
Full example is uploaded on my repository.
After we initialise go project with go mod init
we follow it up with initing air project with air init
.
This creates a new file .air.toml
with default values that air uses when you run the watcher.
We can create a simple main.go
file inside the root project which we will use for testing our debugger.
package main
import "fmt"
func main() {
a := 1
b := 2
c := a + b
fmt.Printf("%d + %d = %d\n", a, b, c)
}
We can test the setup if we run air
which should output the following:
❯ air
__ _ ___
/ /\ | | | |_)
/_/--\ |_| |_| \_ v1.62.0, built with Go go1.24.2
watching .
!exclude tmp
building...
running...
1 + 2 = 3
Process Exit with Code 0
Now lets use delve to actually create a binary which we can debug!
Inside .air.toml
we have to modify cmd
and full_bin
properties:
[build]
cmd = "CGO_ENABLED=0 go build -gcflags=all=\"-N -l\" -o ./tmp/main ."
full_bin = "dlv --listen=127.0.0.1:2345 --headless=true --api-version=2 --accept-multiclient exec ./tmp/main"
...
Explaining -gcflags=all="-N -l"
;
-N
disables compiler optimizations
-l
disables function inlining
all=
applies these flags to all packages being built
Mostly we just ask compiler to not optimize things.
If we go to air's repository we can see inside air_example.toml how they explain full_bin
# Customize binary, can setup environment variables when run your app.
full_bin = "APP_ENV=dev APP_USER=air ./tmp/main"
in our case we actually tell it to run the dlv
debugger instead of just running the binary! Important param is this: --listen=127.0.0.1:2345
which we will have to setup in the IDEs to listen on this port for any information that debugger is sending.
If we run air
now - we see it prints another line:
API server listening at: 127.0.0.1:2345
which means we are successfully listening with delve!
IDE setup with goland & vscode
Goland
I will attach screenshots from my IDE.
But general things that you need to do is add a new Debug configuration of type Go Remote
- presets are generally setup to work with you out of the box!
So now if we set a breakpoint in the main()
method then click debug icon and then run air
we should see the breakpoint being triggered!
Success!
VSCode
We need to add information inside the launch.json
your-project/
├── .vscode/
│ └── launch.json
...
We add the configuration that is very similar to settings in GoLand:
{
"version": "0.2.0",
"configurations": [
{
"name": "Connect to Air Debugger",
"type": "go",
"request": "attach",
"mode": "remote",
"remotePath": "${workspaceFolder}",
"port": 2345,
"host": "127.0.0.1",
"showLog": true,
"trace": "verbose",
"logOutput": "rpc"
}
]
}
Try it out!
Give feedback!
Thanks for reading! :)