Using Makefile in Go Projects (The Practical Way)

Using Makefile in Go Projects (The Practical Way)

Learn how to use Makefile in Go projects with practical examples. Build, run, dev with live reload for your Go development workflow.

Go already gives you a solid toolchain, but once a project grows, repeating commands gets old fast. A simple Makefile gives you standardized commands, less typing, and zero dependencies.

This post shows a minimal, useful Makefile for Go projects:

  • make build → builds to bin/projectname
  • make run → runs the built binary
  • make dev → live reload with air
  • make clean → removes build artifacts
  • make help → self-documented commands

Project Structure

.
├── cmd/
│   └── projectname/
│       └── main.go
├── bin/
├── air.toml
├── go.mod
├── Makefile

Why Use Makefile with Go?

  • One command everyone remembers
  • Same workflow across OSes
  • CI-friendly
  • Self-documenting
  • No bash scripts scattered around

Go stays simple, Make just glues things together.


The Makefile

APP_NAME := projectname
BIN_DIR := bin
BIN_PATH := $(BIN_DIR)/$(APP_NAME)

.PHONY: build run dev clean help

## build: Build the Go binary
build:
  @mkdir -p $(BIN_DIR)
  go build -o $(BIN_PATH) ./cmd/$(APP_NAME)

## run: Run the built binary
run: build
  @./$(BIN_PATH)

## dev: Run with live reload using air
dev:
  @air

## clean: Remove build artifacts
clean:
  @rm -rf $(BIN_DIR)

## help: Show available commands
help:
  @echo ""
  @echo "Available commands:"
  @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) \
    | awk 'BEGIN {FS = ":.*?## "}; {printf "  %-10s %s\n", $$1, $$2}'

make build

make build
  • Compiles your app
  • Output goes to bin/projectname
  • No surprises, no magic paths

This keeps your repo clean and binaries out of the way.


make run

make run
  • Ensures the binary is built
  • Executes ./bin/projectname

Simple dependency chain:

run: build

make dev (Live Reload)

Uses Air for hot reload.

make dev

Make sure Air is installed:

go install github.com/air-verse/air@latest

And you have an air.toml:

root = "."
tmp_dir = "tmp"

[build]
cmd = "go build -o bin/projectname ./cmd/projectname"
bin = "bin/projectname"

make clean

make clean

Deletes: bin/

Useful for:

  • fresh builds
  • CI
  • sanity resets

make help

make help

Outputs something like:

Available commands:
  build      Build the Go binary
  run        Run the built binary
  dev        Run with live reload using air
  clean      Remove build artifacts
  help       Show available commands

This works because of the ## comments — small trick, big win.


Final Notes

  • Keep Makefiles boring
  • Don’t over-abstract
  • If a command needs explaining, it’s probably wrong

For Go projects, this setup hits the sweet spot: simple, readable, and production-safe.

Done.

Album of the blog: