Master Makefile for project automation. Learn variables, patterns, phony targets, parallel execution, and organize development workflows with make commands.
Makefile for Modern Development
Project Structure Makefile
# Makefile
.PHONY: all install dev build test lint clean deploy help
# Default target
.DEFAULT_GOAL := help
# Variables
APP_NAME := myapp
VERSION := $(shell git describe --tags --abbrev=0 2>/dev/null || echo "v0.1.0")
COMMIT := $(shell git rev-parse --short HEAD)
BUILD_TIME := $(shell date -u +"%Y-%m-%dT%H:%M:%SZ")
# Docker
IMAGE := ghcr.io/myorg/$(APP_NAME)
REGISTRY := ghcr.io
# Colors
GREEN := \033[0;32m
NC := \033[0m
##@ Development
install: ## Install dependencies
npm ci
dev: ## Start development server
npm run dev
build: ## Build for production
npm run build
type-check: ## Run TypeScript type check
npx tsc --noEmit
##@ Testing
test: ## Run tests
npm test
test-watch: ## Run tests in watch mode
npm test -- --watch
test-coverage: ## Run tests with coverage
npm test -- --coverage
lint: ## Run linting
npm run lint
lint-fix: ## Fix linting errors
npm run lint -- --fix
##@ Docker
docker-build: ## Build Docker image
docker build --build-arg VERSION=$(VERSION) --build-arg COMMIT=$(COMMIT) --build-arg BUILD_TIME=$(BUILD_TIME) -t $(IMAGE):$(VERSION) -t $(IMAGE):latest .
docker-push: docker-build ## Build and push Docker image
docker push $(IMAGE):$(VERSION)
docker push $(IMAGE):latest
docker-run: ## Run Docker container locally
docker run --rm -p 3000:3000 --env-file .env $(IMAGE):latest
##@ Deployment
deploy-staging: docker-push ## Deploy to staging
kubectl set image deployment/$(APP_NAME) $(APP_NAME)=$(IMAGE):$(VERSION) -n staging
kubectl rollout status deployment/$(APP_NAME) -n staging
deploy-prod: docker-push ## Deploy to production (requires confirmation)
@echo "Deploying $(VERSION) to production..."
@read -p "Are you sure? [y/N] " confirm && [ "$confirm" = "y" ]
kubectl set image deployment/$(APP_NAME) $(APP_NAME)=$(IMAGE):$(VERSION) -n production
##@ Utilities
clean: ## Clean build artifacts
rm -rf dist build .next coverage node_modules/.cache
setup: install ## Full project setup
cp -n .env.example .env || true
@echo "$(GREEN)Setup complete! Edit .env with your credentials.$(NC)"
db-migrate: ## Run database migrations
npx prisma migrate deploy
db-reset: ## Reset development database
npx prisma migrate reset --force
##@ Help
help: ## Show this help message
@awk 'BEGIN {FS = ":.*##"; printf "
Usage:
make \033[36m<target>\033[0m
"} /^[a-zA-Z_0-9-]+:.*?##/ { printf " \033[36m%-20s\033[0m %s
", $1, $2 } /^##@/ { printf "
\033[1m%s\033[0m
", substr($0, 5) }' $(MAKEFILE_LIST)
Pattern Rules and Functions
# Pattern rule - compile all .ts files
BUILD_DIR := dist
SRC_DIR := src
TS_FILES := $(shell find $(SRC_DIR) -name '*.ts')
JS_FILES := $(TS_FILES:$(SRC_DIR)/%.ts=$(BUILD_DIR)/%.js)
$(BUILD_DIR)/%.js: $(SRC_DIR)/%.ts
npx tsc --outDir $(BUILD_DIR) lt;
# Use functions
FILES := $(wildcard src/**/*.ts)
BASENAME := $(notdir $(FILES))
DIRS := $(sort $(dir $(FILES)))
# String functions
UPPER_NAME := $(shell echo $(APP_NAME) | tr a-z A-Z)
TRIMMED := $(strip $(FILES))
Parallel Execution
# Run tests and linting in parallel
ci:
$(MAKE) -j2 test lint
# Parallel builds
build-all:
$(MAKE) -j4 build-frontend build-backend build-worker build-scheduler
Conditional Logic
# Platform detection
UNAME := $(shell uname -s)
ifeq ($(UNAME), Darwin)
OPEN := open
SED := gsed
else
OPEN := xdg-open
SED := sed
endif
# Environment-based config
ENV ?= development
ifeq ($(ENV), production)
DOCKER_FLAGS := --no-cache
NODE_FLAGS := --max-old-space-size=4096
else
DOCKER_FLAGS :=
NODE_FLAGS :=
endif
# Check for required tools
check-tools:
@which docker > /dev/null || (echo "Docker not found" && exit 1)
@which kubectl > /dev/null || (echo "kubectl not found" && exit 1)
@which node > /dev/null || (echo "Node.js not found" && exit 1)
@echo "All required tools found"
Makefile Best Practices
| Practice |
Why |
.PHONY targets |
Don't conflict with files |
## comments |
Show in make help |
| Default goal |
Clear entry point |
| Check dependencies |
Fail early if missing |
| Parallel flags |
Faster builds |