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 helpeliminate 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 helpself-documents available commands- New developers run
make devwithout 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.”