Docs / Automation & IaC / How to Use Make and Makefiles for DevOps Tasks

How to Use Make and Makefiles for DevOps Tasks

By Admin · Mar 2, 2026 · Updated Apr 23, 2026 · 27 views · 3 min read

How to Use Make and Makefiles for DevOps Tasks

GNU Make is traditionally a build tool for compiling software, but it excels as a task runner for DevOps workflows. A Makefile provides a single entry point for common operations on your Breeze instances, replacing scattered shell scripts with a documented, tab-complete interface.

Makefile Basics

A Makefile consists of targets, prerequisites, and recipes. Create a Makefile in your project root:

# Variables
APP_NAME := myapp
VERSION  := $(shell git describe --tags --always 2>/dev/null || echo "dev")
DEPLOY_HOST := breeze-web-01
DEPLOY_USER := deploy
DEPLOY_PATH := /var/www/$(APP_NAME)

.PHONY: help build test deploy clean

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

DevOps Task Targets

Define targets for common operations:

build: ## Build the application
	@echo "Building $(APP_NAME) v$(VERSION)..."
	docker build -t $(APP_NAME):$(VERSION) .
	docker tag $(APP_NAME):$(VERSION) $(APP_NAME):latest

test: ## Run the test suite
	@echo "Running tests..."
	docker run --rm $(APP_NAME):$(VERSION) npm test

lint: ## Run linters
	shellcheck scripts/*.sh
	hadolint Dockerfile

deploy: build test ## Deploy to production Breeze instance
	@echo "Deploying $(APP_NAME) v$(VERSION) to $(DEPLOY_HOST)..."
	rsync -avz --delete \
		--exclude='.git' \
		--exclude='node_modules' \
		./ $(DEPLOY_USER)@$(DEPLOY_HOST):$(DEPLOY_PATH)/
	ssh $(DEPLOY_USER)@$(DEPLOY_HOST) 'cd $(DEPLOY_PATH) && make install'

install: ## Install on server (run on Breeze instance)
	npm ci --production
	sudo systemctl restart $(APP_NAME)

rollback: ## Rollback to previous version
	ssh $(DEPLOY_USER)@$(DEPLOY_HOST) 'cd $(DEPLOY_PATH) && git checkout HEAD~1 && make install'

Infrastructure Management Targets

provision: ## Provision a new Breeze instance
	terraform init
	terraform plan -out=tfplan
	terraform apply tfplan

configure: ## Run Ansible configuration
	ansible-playbook -i inventory/production site.yml

configure-dry: ## Dry-run Ansible configuration
	ansible-playbook -i inventory/production site.yml --check --diff

backup: ## Create a database backup
	@echo "Creating backup..."
	ssh $(DEPLOY_USER)@$(DEPLOY_HOST) '/usr/local/bin/backup-db.sh'
	@echo "Backup complete"

logs: ## Tail production logs
	ssh $(DEPLOY_USER)@$(DEPLOY_HOST) 'journalctl -u $(APP_NAME) -f'

status: ## Check service status
	@ssh $(DEPLOY_USER)@$(DEPLOY_HOST) 'systemctl status $(APP_NAME) --no-pager'
	@ssh $(DEPLOY_USER)@$(DEPLOY_HOST) 'df -h / | tail -1'
	@ssh $(DEPLOY_USER)@$(DEPLOY_HOST) 'free -h | grep Mem'

ssh: ## SSH into the Breeze instance
	ssh $(DEPLOY_USER)@$(DEPLOY_HOST)

Environment-Specific Targets

# Use environment variables for different targets
ENV ?= production

deploy-staging: ENV=staging
deploy-staging: deploy ## Deploy to staging

deploy-prod: ENV=production
deploy-prod: deploy ## Deploy to production

config-file:
	@echo "Using config for $(ENV)"
	cp config/$(ENV).env .env

Conditional Logic and Checks

check-env: ## Verify required environment variables
ifndef API_KEY
	$(error API_KEY is not set)
endif
ifndef DB_PASSWORD
	$(error DB_PASSWORD is not set)
endif
	@echo "Environment check passed"

clean: ## Remove build artifacts
	rm -rf dist/ build/ *.tar.gz
	docker rmi $(APP_NAME):$(VERSION) 2>/dev/null || true
	@echo "Cleaned up"

Best Practices

  • Use .PHONY — declare non-file targets as phony to avoid conflicts with filenames
  • Add help target — use the ## comment pattern for self-documenting targets
  • Use variables — centralize hostnames, paths, and versions at the top
  • Chain dependenciesdeploy: build test ensures build and test run before deploy
  • Use @ prefix — suppress recipe echoing for cleaner output
  • Use tabs, not spaces — Makefile recipes require tab indentation
  • Keep it simple — if a target grows beyond 10 lines, move logic to a shell script and call it from Make

A well-crafted Makefile gives your team a consistent, discoverable interface for managing Breeze infrastructure and deployments.

Was this article helpful?