Skip to content

Taskfile: Modern Task Runner for Any Project

DodaTech Updated 2026-06-22 5 min read

In this tutorial, you'll learn Taskfile including task dependencies, variables, templating, cross-platform support, and using Task as a modern alternative to Make for any programming language.

Why Taskfile Matters

Make is universal but its syntax is cryptic. Tabs vs spaces, legacy variable syntax, and platform-specific commands make Makefiles error-prone. Task brings a clean YAML syntax, native cross-platform support, task dependencies, and built-in templating. It is a single binary with no dependencies.

By the end of this guide, you will write Taskfiles for any project, use dependencies and variables, and replace Makefiles with cleaner Taskfile equivalents.

What is Task?

Task is a task runner and build tool written in Go. It reads a Taskfile.yml and executes tasks with dependencies, variables, and environment-specific configurations.

flowchart LR
  A[Taskfile.yml] --> B[Task: build]
  A --> C[Task: test]
  A --> D[Task: lint]
  B --> E[Dependencies]
  E --> F[Task: install-deps]
  B --> G[Commands]
  G --> H[cmds: [go build, npm run build]]
  C --> I[cmds: [go test, npm test]]

Installation

# macOS
brew install go-task

# Linux (script)
sh -c "$(curl -ssL https://taskfile.dev/install.sh)" -- -d

# Verify
task --version
# Task version: 3.38.0

Your First Taskfile

# Taskfile.yml
version: '3'

tasks:
  hello:
    cmds:
      - echo "Hello, Task!"
    silent: true
task hello

Expected Output

Hello, Task!

Tasks with Dependencies

version: '3'

tasks:
  build:
    cmds:
      - go build -o app .

  generate:
    cmds:
      - go generate ./...

  install-deps:
    cmds:
      - go mod download
      - npm install

  test:
    deps: [install-deps]
    cmds:
      - go test ./...
      - npm test

  all:
    deps: [generate, build, test]
task test
# Runs install-deps first, then test

Variables

version: '3'

vars:
  APP_NAME: myapp
  BUILD_DIR: dist
  GO_FLAGS: -ldflags="-s -w"

tasks:
  build:
    cmds:
      - mkdir -p {{.BUILD_DIR}}
      - go build {{.GO_FLAGS}} -o {{.BUILD_DIR}}/{{.APP_NAME}} .
    env:
      CGO_ENABLED: '0'
      GOOS: linux

Task-Level Variables

version: '3'

tasks:
  greet:
    vars:
      NAME: '{{default "World" .NAME}}'
    cmds:
      - echo "Hello, {{.NAME}}!"

# Usage: task greet NAME=Alice
# Output: Hello, Alice!

Dynamic Variables

version: '3'

tasks:
  version:
    cmds:
      - echo "{{.DATE}}-{{.GIT_HASH}}"
    vars:
      DATE:
        sh: date +%Y%m%d
      GIT_HASH:
        sh: git rev-parse --short HEAD

Cross-Platform Support

Task handles cross-platform quirks natively.

version: '3'

tasks:
  install:
    cmds:
      - task: install-{{OS}}

  install-linux:
    cmds:
      - sudo apt-get install -y libssl-dev

  install-darwin:
    cmds:
      - brew install openssl

  install-windows:
    cmds:
      - choco install openssl

Platform-Specific Commands

version: '3'

tasks:
  clean:
    cmds:
      - |
        {{if eq OS "windows"}}
          del /f /q {{.BUILD_DIR}}\*
        {{else}}
          rm -rf {{.BUILD_DIR}}/*
        {{end}}

Real-World Taskfiles

Go Project

version: '3'

vars:
  APP: server
  VERSION: '{{default "dev" .VERSION}}'

tasks:
  default:
    deps: [build]

  install-deps:
    cmds:
      - go mod download

  build:
    deps: [install-deps]
    cmds:
      - go build -ldflags="-X main.version={{.VERSION}}" -o {{.APP}} .

  test:
    deps: [install-deps]
    cmds:
      - go test -v -race -cover ./...

  lint:
    cmds:
      - golangci-lint run ./...

  run:
    deps: [build]
    cmds:
      - ./{{.APP}}

  clean:
    cmds:
      - rm -f {{.APP}}
      - rm -rf dist/

  dev:
    deps: [build]
    cmds:
      - ./{{.APP}}
    sources:
      - ./**/*.go
    watch: true

Node.js Project

version: '3'

vars:
  NODE_OPTIONS: '--max-old-space-size=4096'

tasks:
  install:
    cmds:
      - npm ci

  dev:
    deps: [install]
    cmds:
      - npm run dev

  build:
    deps: [install]
    cmds:
      - npm run build

  test:
    deps: [install]
    cmds:
      - npm test
    env:
      CI: 'true'

  lint:
    deps: [install]
    cmds:
      - npm run lint

  format:
    cmds:
      - npx prettier --write 'src/**/*.{js,ts,jsx,tsx}'

  docker-build:
    cmds:
      - docker build -t myapp:{{.VERSION}} .

Python Project

version: '3'

vars:
  VENV: .venv
  PYTHON: '{{default "python3" .PYTHON}}'

tasks:
  venv:
    status:
      - test -d {{.VENV}}
    cmds:
      - '{{.PYTHON}} -m venv {{.VENV}}'

  install:
    deps: [venv]
    cmds:
      - '{{.VENV}}/bin/pip install -r requirements.txt'

  dev:
    deps: [install]
    cmds:
      - '{{.VENV}}/bin/uvicorn app.main:app --reload'

  test:
    deps: [install]
    cmds:
      - '{{.VENV}}/bin/pytest -v tests/'

  lint:
    deps: [install]
    cmds:
      - '{{.VENV}}/bin/flake8 src/'
      - '{{.VENV}}/bin/mypy src/'

  clean:
    cmds:
      - rm -rf {{.VENV}}
      - find . -type d -name __pycache__ -exec rm -rf {} + 2>/dev/null || true

Taskfile Includes

version: '3'

includes:
  docker: ./docker/Taskfile.yml
  deploy: ./deploy/Taskfile.yml

tasks:
  build:
    deps:
      - docker:build

Using Go Templates

version: '3'

tasks:
  greet:
    cmds:
      - |
        echo "{{if .NAME}}Hello, {{.NAME}}!{{else}}Hello, World!{{end}}"

  list:
    cmds:
      - |
        {{range .ITEMS}}
          echo "Item: {{.}}"
        {{end}}

Comparison to Make

Feature Make Task
Configuration syntax Makefile (tab-based) Taskfile.yml (YAML)
Cross-platform Poor (shell-dependent) Excellent (built-in OS detection)
Task dependencies Yes (target-based) Yes (deps array)
Variables $(VAR) {{.VAR}} (Go templates)
Default task First target default task
Watch mode No Built-in (watch: true)
Silent commands @ prefix silent: true

Common Errors

Problem Cause Fix
yaml: unmarshal errors Invalid YAML syntax Check indentation (2 spaces) and quotes
task: No Taskfile.yml found Wrong directory Ensure you are in the directory with the Taskfile
undefined variable "VAR" Variable not defined Use {{default "value" .VAR}} for optional vars
command not found Tool not installed Add an install-deps task or document prerequisites
watch: need sources Watch mode requires sources list Add sources: with glob patterns

Practice Questions

1. What file does Task read for configuration?

Taskfile.yml.

2. How do you create a task dependency in Task?

Use the deps: field with a list of task names.

3. How do you access a variable in a Taskfile?

{{.VARIABLE_NAME}} using Go template syntax.

4. How do you make a task run silently (no command echo)?

Set silent: true in the task definition.

5. How does Task handle cross-platform differences?

It provides the built-in {{OS}} variable and supports conditional expressions.

Challenge

Create a Taskfile.yml for a multi-language project that uses Node.js for the frontend and Python for the backend. Include tasks for: installing dependencies for both, running both dev servers simultaneously, running all tests, building for production, and Docker image creation. Use cross-platform friendly commands.

Real-World Task

Replace an existing Makefile or npm scripts with a Taskfile in a project you work on. Include all the same functionality: build, test, lint, format, clean, and deploy. Add watch mode for development. Compare the experience and document the Migration steps.

Should I use Task or Make?

Use Task for new projects, especially cross-platform ones. Use Make if you need maximum portability (it is pre-installed everywhere) or are working on a C/C++ project where Make is standard.

Can I call shell scripts from Task?

Yes. Task commands are executed through the shell. You can call any Shell Script: cmds: ["./scripts/deploy.sh"].

Does Task support parallel task execution?

Yes. Use parallel: true in a task or let Task run dependencies in parallel by default when they have no interdependencies.

Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro