One the drawbacks of debugging go code with VSCode is that when you make a change, the project should recompile automatically and start debugging. Enter air. Air provides live reload for go apps and has made developing go applications much easier. As our applications have gotten more complex, we wanted to integrate air with the VSCode debugging process. It was a bit tricky to setup, so I thought I would share our configuration.

First, you will need to install air and then configure it within your project. Then you will need to install Delve. Delve is a debugger for Go and the debugger that VSCode uses internally for Go. We use make to build all of our projects so for the sake of this example, I will include just the steps needed for this setup. This will remove previous binaries and then build a new binary with the debugging flags enabled. The resulting binary will be called ./bin/my-app-debug. Note, I ignored all the binaries in the ./bin directory using .gitignore.

# the name of the binary when built
BINARY_NAME=my-app

# remove any binaries that are built
clean:
	rm -f ./bin/$(BINARY_NAME)*

build-debug: clean
	CGO_ENABLED=0 go build -gcflags=all="-N -l" -o bin/$(BINARY_NAME)-debug main.go

Once we have make configured it is time configure air. Drop a configuration file in your project called .air.toml. The configuration below build our project using the make file we created above, then run the application using dlv exposing port 2345 for the debugger client. When changes are made to your app this will reload. You may need to adjust the args_bin setting to configure your application.

# Config file for [Air](https://github.com/cosmtrek/air) in TOML format
root = "."
tmp_dir = "tmp"

[build]
cmd = "make build-debug"
bin = "./bin/my-app-debug"
full_bin = "dlv exec ./bin/my-app-debug --listen=127.0.0.1:2345 --headless=true --api-version=2 --accept-multiclient --continue --log -- "
include_ext = ["go"]
exclude_dir = [".vscode", ".github", "bin", "tmp"]
exclude_regex = ["_test.go"]
exclude_unchanged = true.
args_bin = ["server"]

[misc]
clean_on_exit = true

[screen]
clear_on_rebuild = true
keep_scroll = true

Once we have air configured we can run this from the command line by running air in our project directory. Once the process is running we need to connect VSCode. Drop the following configuration in your .vscode/launch.json file.

{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Attach to Air",
      "type": "go",
      "mode": "remote",
      "request": "attach",
      "host": "127.0.0.1",
      "port": 2345
    }
  ]
}

Now, you will be able to attach your VSCode debugger to the locally running dlv process on port 2345 started by air. That’s it, happy debugging!

For reference these are the commands for creating the bin directory:

mkdir -p ./bin
touch ./bin/.gitkeep

Then ignoring the binaries within the bin directory:

/bin/*
!.gitkeep