Taskfile Cheat Sheet
Overview
Task (also called Taskfile) is a task runner written in Go that uses YAML-based configuration files. It serves as a simpler, cross-platform alternative to GNU Make, with built-in support for file watching, parallel execution, environment variables, and conditional task execution based on file checksums or timestamps.
Task is distributed as a single binary with no dependencies, making it easy to install and use across development teams. Its YAML syntax is more approachable than Makefile syntax, and it avoids common Make pitfalls like tab-sensitivity and implicit rules.
Installation
# macOS
brew install go-task
# Linux (install script)
sh -c "$(curl --location https://taskfile.dev/install.sh)" -- -d -b /usr/local/bin
# Snap
sudo snap install task --classic
# Go install
go install github.com/go-task/task/v3/cmd/task@latest
# npm (wrapper)
npm install -g @go-task/cli
# Windows
choco install go-task
# or
winget install Task.Task
# Verify
task --version
Core Commands
| Command | Description |
|---|---|
task | Run the default task |
task <name> | Run a specific task |
task --list | List available tasks |
task --list-all | List all tasks including internal |
task --summary <name> | Show task details |
task --dry | Print commands without running |
task --watch <name> | Watch files and re-run task |
task --parallel t1 t2 | Run tasks in parallel |
task --force <name> | Force run ignoring up-to-date checks |
task --init | Create a starter Taskfile.yml |
Taskfile Syntax
Basic Taskfile.yml
version: '3'
vars:
APP_NAME: myapp
VERSION: 1.0.0
tasks:
default:
desc: "Build and test the project"
cmds:
- task: build
- task: test
build:
desc: "Compile the application"
cmds:
- go build -o {{.APP_NAME}} ./cmd/{{.APP_NAME}}
test:
desc: "Run test suite"
cmds:
- go test ./...
clean:
desc: "Remove build artifacts"
cmds:
- rm -f {{.APP_NAME}}
Tasks with Dependencies
version: '3'
tasks:
deploy:
desc: "Deploy to production"
deps: [build, lint]
cmds:
- echo "Deploying..."
- scp ./app server:/opt/app/
build:
cmds:
- go build -o app .
lint:
cmds:
- golangci-lint run
Variables and Environment
version: '3'
vars:
GIT_COMMIT:
sh: git rev-parse --short HEAD
BUILD_DATE:
sh: date -u +%Y-%m-%dT%H:%M:%SZ
env:
CGO_ENABLED: '0'
GOFLAGS: -trimpath
tasks:
build:
desc: "Build with version info"
vars:
LDFLAGS: >-
-X main.version={{.VERSION}}
-X main.commit={{.GIT_COMMIT}}
cmds:
- go build -ldflags "{{.LDFLAGS}}" -o app .
dev:
desc: "Run with local env"
dotenv: ['.env', '.env.local']
cmds:
- go run ./cmd/server
Configuration
Task Options
version: '3'
tasks:
silent-task:
desc: "Runs silently"
silent: true
cmds:
- echo "This won't be printed as command"
directory-task:
desc: "Runs in specific directory"
dir: ./frontend
cmds:
- npm run build
interactive:
desc: "Interactive task"
interactive: true
cmds:
- vim config.yaml
ignore-errors:
desc: "Continue on error"
cmds:
- cmd: rm -f nonexistent.file
ignore_error: true
- echo "This still runs"
platforms:
desc: "Platform-specific task"
platforms: [linux, darwin]
cmds:
- echo "Only runs on Linux or macOS"
Source and Checksum-Based Execution
version: '3'
tasks:
build:
desc: "Build only when sources change"
sources:
- src/**/*.go
- go.mod
- go.sum
generates:
- bin/app
cmds:
- go build -o bin/app .
install-deps:
desc: "Install deps only when package.json changes"
sources:
- package.json
- package-lock.json
generates:
- node_modules/.package-lock.json
method: checksum
cmds:
- npm ci
assets:
desc: "Rebuild assets based on timestamp"
sources:
- assets/scss/**/*.scss
generates:
- public/css/style.css
method: timestamp
cmds:
- sass assets/scss/main.scss public/css/style.css
File Watching
version: '3'
tasks:
dev:
desc: "Watch and rebuild"
watch: true
sources:
- src/**/*.go
cmds:
- go build -o bin/app .
- echo "Rebuilt successfully"
# Watch mode from CLI
task --watch build
# Watch multiple tasks
task --watch --parallel build test
Advanced Usage
Including Other Taskfiles
version: '3'
includes:
docker:
taskfile: ./tasks/DockerTasks.yml
dir: .
frontend:
taskfile: ./frontend/Taskfile.yml
dir: ./frontend
optional:
taskfile: ./local.yml
optional: true
tasks:
all:
cmds:
- task: docker:build
- task: frontend:build
Conditional Execution
version: '3'
tasks:
deploy:
desc: "Deploy to production"
preconditions:
- sh: test -f .env.production
msg: "Missing .env.production file"
- sh: git diff --quiet
msg: "Uncommitted changes detected"
cmds:
- ./deploy.sh
setup:
desc: "Setup only if not done"
status:
- test -f config.yaml
- test -d node_modules
cmds:
- cp config.example.yaml config.yaml
- npm install
Parallel Execution and Looping
version: '3'
tasks:
services:
desc: "Start all services in parallel"
deps:
- task: start-service
vars: { SERVICE: api }
- task: start-service
vars: { SERVICE: worker }
- task: start-service
vars: { SERVICE: scheduler }
start-service:
internal: true
cmds:
- echo "Starting {{.SERVICE}}..."
- docker compose up -d {{.SERVICE}}
lint-all:
desc: "Lint everything"
cmds:
- for: [go, js, css]
cmd: echo "Linting {{.ITEM}} files..."
- for:
var: DIRS
cmd: golangci-lint run {{.ITEM}}/...
vars:
DIRS: cmd pkg internal
CLI Arguments
version: '3'
tasks:
run:
desc: "Run app with arguments"
cmds:
- go run . {{.CLI_ARGS}}
migrate:
desc: "Run migration (usage: task migrate -- up)"
cmds:
- migrate -database $DB_URL {{.CLI_ARGS}}
# Pass arguments after --
task run -- --port 8080 --debug
task migrate -- up
Troubleshooting
| Issue | Solution |
|---|---|
| Task up-to-date when it shouldn’t be | Use task --force <name> or delete .task/ directory |
| Variable not expanding | Use {{.VAR_NAME}} syntax with dot prefix |
| Task not found | Check indentation in YAML and task name spelling |
| Watch not triggering | Ensure sources patterns match your files |
| Included taskfile not found | Check path is relative to the including Taskfile |
| Environment variable not set | Use env: block or dotenv: for .env files |
# Debug: dry run
task --dry build
# Show task details
task --summary build
# Force run ignoring status/sources
task --force build
# Clear task checksums
rm -rf .task/
# Verbose output
task --verbose build