Skip to content

Up-to-date checks ​

A build should run when its inputs change or its output is missing. Declare those files with sources and generates, and Task can skip the commands on your next run. For other kinds of work, use status to check whether the result is already available.

Skip unchanged builds ​

For a Go application in main.go, declare the source file and the executable that the build produces:

yaml
version: '3'

tasks:
  build:
    sources: [main.go]
    generates: ['app{{exeExt}}']
    cmds:
      - go build -o app{{exeExt}} main.go

Run task build to create the executable. Run it again without changing main.go, and Task reports that build is up to date. Edit main.go or delete the executable, and the next call builds it again.

The default method, checksum, compares the content of source files with a saved fingerprint. It checks that declared outputs exist; it does not compare their contents. Editing the executable alone will not trigger a rebuild.

These checks skip the task's commands. Its dependencies still run first and perform their own up-to-date checks.

Track the right files ​

sources and generates accept files and glob patterns, relative to the task's working directory. Include every file that affects the result, such as source code, configuration, and dependency lockfiles.

For a Go module with several source files, replace sources and cmds in the example above with:

yaml
sources:
  - '**/*.go'
  - go.mod
  - go.sum
  - exclude: '**/*_test.go'
cmds:
  - go build -o app{{exeExt}} .

Patterns are evaluated in order. Put each exclude after the positive glob it narrows. Here, test files are excluded because this task builds the application; a test task should track them.

Set use_gitignore: true at the root of the Taskfile to filter glob matches using .gitignore rules. A task can override that setting. Keep it disabled for tasks that need to track ignored files as inputs.

generates is optional. A task such as a test suite can use sources alone to skip work when its inputs have not changed. generates alone does not provide a file fingerprint; use status if you only need to check that a result exists.

Choose a check method ​

MethodHow it checks sources
checksum (default)Compares file contents with a saved fingerprint.
timestampCompares modification times with outputs and Task's saved timestamp.
noneDisables file-based skipping.

To use modification times for the build above, add method: timestamp to the task:

yaml
tasks:
  build:
    method: timestamp
    sources: [main.go]
    generates: ['app{{exeExt}}']
    cmds:
      - go build -o app{{exeExt}} main.go

You can also set method at the root of the Taskfile to change the default for all tasks. A task's own setting takes precedence.

With timestamp, touching a source can cause a rerun even if its content has not changed. Without generates, Task uses its saved timestamp for the comparison. Use method: none when sources should drive watch mode without making the task up to date.

Check existing work ​

Use status when a command can determine whether work is needed. Every check must exit with code 0 for Task to skip the commands. If any check fails, Task runs the commands:

yaml
version: '3'

tasks:
  prepare:
    status:
      - test -d directory
      - test -f directory/file1.txt
      - test -f directory/file2.txt
    cmds:
      - mkdir -p directory
      - touch directory/file1.txt directory/file2.txt

Run task prepare twice: the first call creates the files, and the second skips the commands. Delete either file, and Task runs the commands again.

Keep status checks fast and read-only: they may run each time the task is called. They can inspect files, installed tools, services, or remote artifacts. A failed check means "do the work", so the commands should handle partially completed work, as mkdir -p does above.

If a failed check should stop execution with an error, use preconditions.

Combine files and status ​

Use both sources and status when the result depends on local files but cannot be checked with generates. This Docker example tags the image with a checksum of its build inputs:

yaml
version: '3'

tasks:
  image:
    sources:
      - Dockerfile
      - src/**/*
    status:
      - docker image inspect example/app:{{.CHECKSUM}} > /dev/null 2>&1
    cmds:
      - docker build -t example/app:{{.CHECKSUM}} .

Task skips the build only when the sources are unchanged and the status check succeeds. A changed source produces a new tag; a missing image makes the check fail. Include any other files used by your Dockerfile in sources.

You can also combine sources, generates, and status: every configured check must pass for Task to consider the work up to date.

Use source values ​

With method: checksum, {{.CHECKSUM}} contains the source fingerprint. With method: timestamp, {{.TIMESTAMP}} contains the latest source modification time. Both can be used in cmds and status; they describe the sources, not the generated files.

.TIMESTAMP is a Go time.Time value. For example, {{.TIMESTAMP.Unix}} produces a Unix timestamp, and {{.TIMESTAMP.Format "2006-01-02"}} formats a date.

Check or force a run ​

To check whether tasks are up to date without running their commands:

shell
task --status build

You can pass multiple task names. The command exits with a non-zero exit code if any task is not up to date.

To run a task even when its checks say the work is already done:

shell
task --force build

-f is the short form of --force. To rerun automatically when files change, use Watch mode.

Track different inputs ​

With the checksum method, Task stores one source fingerprint per task label. If build variables affect the result, include them in the label and use separate output paths. For example, to build with different Go build tags:

yaml
version: '3'

tasks:
  build:
    label: 'build-{{.MODE}}'
    sources: [main.go]
    generates: ['app-{{.MODE}}{{exeExt}}']
    cmds:
      - go build -tags '{{.MODE}}' -o app-{{.MODE}}{{exeExt}} main.go

Run task build MODE=debug, then task build MODE=release. Each mode has its own executable and saved checksum, so a later task build MODE=debug can skip the build. A change to main.go makes both modes need a rebuild when next called.

These saved checks apply across invocations. To limit repeated task calls within a single invocation, use run: once or run: when_changed.

Store fingerprints ​

Task stores its file fingerprints in .task/ under the project directory. Usually, add this directory to .gitignore. For generated code committed to version control, you may choose to commit the corresponding checksum too.

Set TASK_TEMP_DIR to store fingerprints elsewhere:

shell
export TASK_TEMP_DIR='~/.task'

Relative paths, such as tmp/task, are resolved from the project directory. Absolute paths and paths starting with ~ use a separate subdirectory for each project.