A Makefile Template for Any Project

Use Make as a project task runner regardless of language or framework.

Key Insights

  • A Makefile is the universal “how do I run this” interface — language-agnostic and available on every Unix system
  • Self-documenting targets with make help eliminate the need for README-based setup instructions
  • CI pipelines and developers use the same commands, ensuring consistency between local and production builds

Make is available on every Unix system. It’s language-agnostic and handles the “how do I run this project” problem better than any README.

The Template

.PHONY: help build run test lint clean dev

help: ## Show this help
	@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-15s\033[0m %s\n", $$1, $$2}'

build: ## Build the application
	go build -o bin/server ./cmd/server

run: build ## Build and run
	./bin/server

dev: ## Run with hot reload
	air -c .air.toml

test: ## Run tests
	go test ./... -race -count=1

lint: ## Run linters
	golangci-lint run

clean: ## Remove build artifacts
	rm -rf bin/ tmp/

migrate-up: ## Run database migrations
	migrate -path migrations -database $(DATABASE_URL) up

migrate-down: ## Rollback last migration
	migrate -path migrations -database $(DATABASE_URL) down 1

docker-build: ## Build Docker image
	docker build -t myapp:latest .

docker-run: docker-build ## Run in Docker
	docker compose up -d

Why This Works

  • make help self-documents available commands
  • New developers run make dev without reading docs
  • CI pipelines use the same commands as developers
  • Language-agnostic — works for Go, Python, Node, Rust, anything

The Default Target

Put this at the top to make make (no arguments) show help:

.DEFAULT_GOAL := help

Every project should have a Makefile. It’s the universal interface for “what can I do with this codebase.”

Liked this? There's more.

Every week: one practical technique, explained simply, with code you can use immediately.