| name | go-taskfile-standards |
| description | Reference knowledge base for the go-taskfile agent. Loaded by that agent on its first iteration when the host has not already injected it; not intended for direct invocation. |
Idiomatic Go-Task Guide
A comprehensive guide to writing clean, maintainable, and idiomatic Taskfiles using go-task.
Table of Contents
Introduction
Go-Task (Task) is a modern, cross-platform task runner and build tool written in Go. It serves as a lightweight alternative to Make, with YAML-based configuration that emphasizes simplicity, cross-platform compatibility, and developer experience.
File Naming and Structure
Standard File Names
Use one of these standard names for your Task files:
Taskfile.yaml (recommended)
Taskfile.yml
Using these standard names enables JSON Schema support in modern editors, providing autocompletion and validation.
Recommended YAML Structure
Follow this conventional order for sections in your Taskfile:
version: '3'
includes:
output: prefixed
silent: false
vars:
env:
tasks:
This structure keeps Taskfiles clean and familiar to other users.
Style Guide
Task Descriptions
Always add descriptions to tasks that will be used by team members:
tasks:
build:
desc: Build the application binary
cmds:
- go build -o app
Tasks with descriptions appear in task --list, making them discoverable for onboarding.
Default Task
Create a default task for the most common operation:
tasks:
default:
desc: Build and test the application
cmds:
- task: build
- task: test
Users can simply run task without arguments to execute the default task.
Commit Your Taskfile
Always commit your Taskfile to version control and document common tasks in your README. This significantly reduces onboarding friction for new team members.
Organization Best Practices
Task Grouping with Includes
Use includes to organize related tasks and create namespaces:
version: '3'
includes:
docker:
taskfile: ./docker/Taskfile.yml
dir: ./docker
lint:
taskfile: ./lint/Taskfile.yml
tasks:
build:
desc: Build everything
cmds:
- task: docker:build
- task: lint:all
Benefits:
- Prevents task name conflicts
- Groups related functionality
- Enables reusable task modules
Subdirectory Taskfiles
Place Taskfile.yaml files in subdirectories to provide context-specific tasks:
project/
├── Taskfile.yaml # Root tasks
├── backend/
│ └── Taskfile.yaml # Backend-specific tasks
└── frontend/
└── Taskfile.yaml # Frontend-specific tasks
When you cd into a subdirectory and run task, it uses the local Taskfile, allowing context-appropriate task definitions.
Variables in Includes
Pass variables to included Taskfiles for customization:
includes:
api:
taskfile: ./services/Taskfile.yml
vars:
SERVICE_NAME: api
PORT: 8080
worker:
taskfile: ./services/Taskfile.yml
vars:
SERVICE_NAME: worker
PORT: 8081
This enables reusable Taskfiles that can be included multiple times with different configurations.
Variables and Environment
Variable Types
Static Variables:
vars:
APP_NAME: myapp
VERSION: 1.0.0
Dynamic Variables (Shell Commands):
vars:
GIT_COMMIT:
sh: git rev-parse --short HEAD
BUILD_TIME:
sh: date -u +"%Y-%m-%dT%H:%M:%SZ"
Task-Specific Variables:
tasks:
build:
vars:
BUILD_FLAGS: -ldflags "-X main.version={{.VERSION}}"
cmds:
- go build {{.BUILD_FLAGS}} -o {{.APP_NAME}}
Variable Precedence
Variables follow this priority order (highest to lowest):
- Command-line variables (
task VAR=value taskname)
- Task-specific variables
- Global variables
- Environment variables
Principle: The closer to the task definition, the higher the priority.
Environment Variables
Global Environment:
env:
GO111MODULE: on
CGO_ENABLED: 0
Task-Specific Environment:
tasks:
test:
env:
TEST_TIMEOUT: 10m
cmds:
- go test ./...
DotEnv Files:
dotenv: ['.env', '{{.HOME}}/.env']
tasks:
run:
cmds:
- ./app
Special Variables
Task provides these built-in variables:
{{.CHECKSUM}} - Checksum of sources (when using checksum method)
{{.TIMESTAMP}} - Timestamp of sources (when using timestamp method)
{{.TASK}} - Current task name
{{.ROOT_DIR}} - Root directory of the Taskfile
{{.TASKFILE_DIR}} - Directory of the current Taskfile
{{.USER_WORKING_DIR}} - Directory from which task was called
Task Dependencies
Basic Dependencies
tasks:
build:
deps: [clean, generate]
cmds:
- go build -o app
clean:
cmds:
- rm -rf dist/
generate:
cmds:
- go generate ./...
Dependencies run before the task's commands. By default, Task waits for all dependencies to complete.
Dependency Execution Order
Dependencies can run in parallel for better performance:
tasks:
test:
deps: [lint, unit-test, integration-test]
cmds:
- echo "All tests passed"
lint:
cmds:
- golangci-lint run
unit-test:
cmds:
- go test -short ./...
integration-test:
cmds:
- go test -tags=integration ./...
All three tasks (lint, unit-test, integration-test) run in parallel.
Fail Fast
Stop on the first dependency failure:
tasks:
deploy:
deps: [build, test]
vars:
failfast: true
cmds:
- ./deploy.sh
Or use the --failfast CLI flag: task --failfast deploy
Dependencies with Variables
Pass variables to dependencies:
tasks:
build-all:
cmds:
- task: build
vars:
PLATFORM: linux
- task: build
vars:
PLATFORM: darwin
build:
cmds:
- GOOS={{.PLATFORM}} go build -o app-{{.PLATFORM}}
Cross-Platform Compatibility
Avoid Shell-Specific Constructs
❌ Bad:
tasks:
clean:
cmds:
- rm -rf dist/
✅ Good:
tasks:
clean:
cmds:
- rm -rf dist/
platforms: [linux, darwin]
clean:windows:
cmds:
- del /Q /S dist\
platforms: [windows]
Platform-Specific Tasks
Restrict tasks to specific platforms:
tasks:
build:linux:
platforms: [linux]
cmds:
- GOOS=linux go build
build:darwin:
platforms: [darwin]
cmds:
- GOOS=darwin go build
build:windows:
platforms: [windows]
cmds:
- set GOOS=windows && go build
Valid values: Any valid GOOS/GOARCH combination (e.g., linux, darwin, windows, linux/amd64, darwin/arm64)
Use Cross-Platform Tools
Prefer Go-based or cross-platform tools:
- Use
go run instead of shell scripts
- Use task built-ins for common operations
- Consider tools like
sh task runner for portable shell commands
Declare Target Shell
tasks:
build:
cmds:
- go build
shopt: ['-e', '-u', '-o', 'pipefail']
Or set globally:
set: [errexit, nounset, pipefail]
tasks:
Change Detection
Sources and Generates
Inform Task about source files and generated outputs to skip unnecessary runs:
tasks:
build:
sources:
- src/**/*.go
- go.mod
- go.sum
generates:
- dist/app
cmds:
- go build -o dist/app
Task tracks these files and only runs if sources changed or generates are missing.
Checksum Method (Recommended)
tasks:
build:
method: checksum
sources:
- '**/*.go'
generates:
- app
cmds:
- go build -o app
Checksum method:
- Takes checksums of dependencies
- Saves them to
.task/ directory
- Compares current vs saved checksums
- More reliable than timestamps
- Works across file copies and git operations
Timestamp Method
tasks:
build:
method: timestamp
sources:
- '**/*.go'
generates:
- app
cmds:
- go build -o app
Timestamp method:
- Compares file modification times
- Simpler but less reliable
- Issues with file copies, git operations
Status Commands
Custom conditions for task freshness:
tasks:
build:
cmds:
- go build -o app
status:
- test -f app
- test "$(find src -newer app | wc -l)" -eq 0
Task runs only if all status commands fail (non-zero exit).
Advanced Features
Watch Mode
Automatically rerun tasks when files change:
tasks:
dev:
watch: true
sources:
- '**/*.go'
cmds:
- go run main.go
Run with: task dev
Silent Tasks
Suppress output:
tasks:
setup:
silent: true
cmds:
- echo "Setting up..."
- mkdir -p dist/
Or per-command:
tasks:
build:
cmds:
- cmd: echo "Building..."
silent: true
- go build
Ignore Errors
Continue on command failure:
tasks:
lint:
cmds:
- cmd: golangci-lint run
ignore_error: true
- staticcheck ./...
Interactive Commands
For commands requiring user input:
tasks:
deploy:
interactive: true
cmds:
- kubectl apply -f manifest.yaml
Deferred Commands
Run cleanup commands even if task fails:
tasks:
test:
cmds:
- docker-compose up -d
- defer: docker-compose down
- go test ./...
The deferred command runs after the task completes or fails.
Task Aliases
tasks:
build:
aliases: [b, compile]
cmds:
- go build
Run with: task b or task compile
Output Modes
Control how task output is displayed:
output: prefixed
tasks:
logs:
output: group
cmds:
- docker logs myapp
Options:
interleaved - Output as it comes (default for single task)
group - Buffer output, print when complete
prefixed - Prefix each line with task name (default for multiple tasks)
CI/CD Integration
Pin Task Version
In CI, always pin the Task version:
- name: Install Task
uses: arduino/setup-task@v1
with:
version: 3.x
- run: |
curl -sL https://taskfile.dev/install.sh | sh -s -- -b /usr/local/bin v3.34.1
Cache Task Binary
- name: Cache Task
uses: actions/cache@v3
with:
path: ~/bin/task
key: ${{ runner.os }}-task-v3.34.1
Run Tasks in PR Checks
- name: Run checks
run: |
task lint
task test
task build
Benefits:
- Consistent local and CI environments
- Single source of truth for build commands
- Easier to test CI changes locally
Environment-Specific Tasks
tasks:
test:ci:
desc: Run tests in CI with coverage
env:
CI: true
cmds:
- go test -v -race -coverprofile=coverage.out ./...
- go tool cover -html=coverage.out -o coverage.html
test:
desc: Run tests locally
cmds:
- go test -short ./...
Monorepo Management
Root Taskfile with Includes
version: '3'
includes:
backend:
taskfile: ./services/backend/Taskfile.yml
dir: ./services/backend
frontend:
taskfile: ./services/frontend/Taskfile.yml
dir: ./services/frontend
shared:
taskfile: ./shared/Taskfile.yml
dir: ./shared
tasks:
default:
desc: Build all services
cmds:
- task: backend:build
- task: frontend:build
test:
desc: Test all services
deps: [backend:test, frontend:test, shared:test]
Dynamic Includes
For discovering Taskfiles automatically:
version: '3'
vars:
SERVICES:
sh: find services -name Taskfile.yml -exec dirname {} \;
tasks:
test-all:
cmds:
- for: { var: SERVICES, split: '\n' }
cmd: task -d {{.ITEM}} test
Shared Variables Across Monorepo
version: '3'
vars:
GO_VERSION: 1.21
DOCKER_REGISTRY: myregistry.io
includes:
backend:
taskfile: ./backend/Taskfile.yml
vars:
SERVICE_NAME: backend
GO_VERSION: '{{.GO_VERSION}}'
REGISTRY: '{{.DOCKER_REGISTRY}}'
Common Patterns
Build Pattern
tasks:
build:
desc: Build the application
sources:
- '**/*.go'
- go.mod
- go.sum
generates:
- dist/{{.APP_NAME}}
vars:
APP_NAME: myapp
BUILD_FLAGS: -ldflags "-X main.version={{.VERSION}} -X main.commit={{.GIT_COMMIT}}"
VERSION:
sh: git describe --tags --always
GIT_COMMIT:
sh: git rev-parse --short HEAD
cmds:
- mkdir -p dist
- go build {{.BUILD_FLAGS}} -o dist/{{.APP_NAME}}
Test Pattern
tasks:
test:
desc: Run all tests
deps: [test:unit, test:integration]
test:unit:
desc: Run unit tests
cmds:
- go test -short -race ./...
test:integration:
desc: Run integration tests
cmds:
- go test -tags=integration ./...
test:coverage:
desc: Run tests with coverage
cmds:
- go test -race -coverprofile=coverage.out ./...
- go tool cover -html=coverage.out -o coverage.html
Docker Pattern
tasks:
docker:build:
desc: Build Docker image
vars:
IMAGE_NAME: myapp
IMAGE_TAG:
sh: git rev-parse --short HEAD
cmds:
- docker build -t {{.IMAGE_NAME}}:{{.IMAGE_TAG}} .
- docker tag {{.IMAGE_NAME}}:{{.IMAGE_TAG}} {{.IMAGE_NAME}}:latest
docker:push:
desc: Push Docker image
deps: [docker:build]
cmds:
- docker push {{.IMAGE_NAME}}:{{.IMAGE_TAG}}
- docker push {{.IMAGE_NAME}}:latest
Cleanup Pattern
tasks:
clean:
desc: Clean build artifacts
cmds:
- rm -rf dist/
- rm -rf .task/
- go clean -cache
clean:all:
desc: Deep clean including dependencies
deps: [clean]
cmds:
- rm -rf vendor/
- go clean -modcache
Development Pattern
tasks:
dev:
desc: Start development server with hot reload
watch: true
sources:
- '**/*.go'
cmds:
- go run main.go
dev:deps:
desc: Start development dependencies (DB, Redis, etc.)
cmds:
- docker-compose -f docker-compose.dev.yml up -d
dev:stop:
desc: Stop development dependencies
cmds:
- docker-compose -f docker-compose.dev.yml down
Lint Pattern
tasks:
lint:
desc: Run all linters
deps: [lint:go, lint:yaml, lint:docker]
lint:go:
desc: Lint Go code
sources:
- '**/*.go'
cmds:
- golangci-lint run ./...
lint:yaml:
desc: Lint YAML files
sources:
- '**/*.yml'
- '**/*.yaml'
cmds:
- yamllint .
lint:docker:
desc: Lint Dockerfiles
sources:
- '**/Dockerfile*'
cmds:
- hadolint Dockerfile
lint:fix:
desc: Auto-fix linting issues
cmds:
- golangci-lint run --fix ./...
Install Dependencies Pattern
tasks:
deps:
desc: Install all dependencies
deps: [deps:go, deps:tools]
deps:go:
desc: Install Go dependencies
sources:
- go.mod
- go.sum
cmds:
- go mod download
- go mod verify
deps:tools:
desc: Install development tools
cmds:
- go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
- go install golang.org/x/tools/cmd/goimports@latest
Release Pattern
tasks:
release:
desc: Create a new release
deps: [test, build]
cmds:
- task: version:bump
- task: git:tag
- task: docker:push
- task: git:push
version:bump:
desc: Bump version
vars:
NEW_VERSION:
sh: echo {{.VERSION}} | awk -F. '{print $1"."$2"."$3+1}'
cmds:
- echo "{{.NEW_VERSION}}" > VERSION
git:tag:
desc: Create git tag
cmds:
- git tag -a v{{.VERSION}} -m "Release v{{.VERSION}}"
git:push:
desc: Push changes and tags
cmds:
- git push origin main
- git push origin --tags
References
Official Documentation
Articles and Tutorials
Community Resources
Go Packages
Last Updated: January 2026
This guide is a living document. Contributions and improvements are welcome!