Makefiles work. They have worked for decades. But they have sharp edges — tab sensitivity, implicit rules, .PHONY everywhere, and arcane syntax for anything beyond the basics.
Taskfile is a YAML-based task runner that does what most people actually use Make for, without the footguns.
Installation
brew install go-task
Basic Taskfile
version: '3'
tasks:
build:
desc: Build the application
cmds:
- go build -o bin/app ./cmd/app
test:
desc: Run all tests
cmds:
- go test ./...
lint:
desc: Run linters
cmds:
- golangci-lint run
dev:
desc: Run with live reload
deps: [build]
cmds:
- air
What I Like
Variables and environment files:
tasks:
deploy:
dotenv: ['.env']
cmds:
- flyctl deploy --app {{.APP_NAME}}
Task dependencies with parallelism:
tasks:
ci:
deps: [lint, test, build]
Dependencies run in parallel by default. No need to wire up & and wait.
Conditional execution:
tasks:
generate:
sources:
- 'proto/**/*.proto'
generates:
- 'gen/**/*.go'
cmds:
- buf generate
The task only runs if source files are newer than generated files.
When to Keep Make
If your project already has a Makefile and the team is comfortable with it, switching gains you nothing. Taskfile shines on new projects and for teams that are tired of debugging tab-vs-space issues.