Skip to content

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

CommandDescription
taskRun the default task
task <name>Run a specific task
task --listList available tasks
task --list-allList all tasks including internal
task --summary <name>Show task details
task --dryPrint commands without running
task --watch <name>Watch files and re-run task
task --parallel t1 t2Run tasks in parallel
task --force <name>Force run ignoring up-to-date checks
task --initCreate 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

IssueSolution
Task up-to-date when it shouldn’t beUse task --force <name> or delete .task/ directory
Variable not expandingUse {{.VAR_NAME}} syntax with dot prefix
Task not foundCheck indentation in YAML and task name spelling
Watch not triggeringEnsure sources patterns match your files
Included taskfile not foundCheck path is relative to the including Taskfile
Environment variable not setUse 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