Skip to main content
When a command is more than one line, use heredoc syntax to keep it readable inline rather than splitting it into multiple commands or an external file.

Syntax

commands = [
  <<-EOT
    your multi-line
    shell command here
  EOT
]
The <<- prefix strips leading whitespace from every line, so you can indent the content to match the surrounding code without affecting the shell command. The closing marker (EOT in the example) must be on its own line. You can use any identifier as the marker, but EOT is conventional.

Example

Run a conditional check inline:
variable "min_coverage" {
  type    = number
  default = 80
}

task "check-coverage" {
  description = "Verify test coverage meets the minimum threshold"
  commands = [
    "go test -coverprofile=coverage.out ./...",
    <<-EOT
      coverage=$(go tool cover -func=coverage.out | grep total | awk '{print $3}' | tr -d '%')
      if [ "${var.min_coverage}" -gt "$coverage" ]; then
        echo "Coverage $coverage% is below the required ${var.min_coverage}%"
        exit 1
      fi
      echo "Coverage $coverage% meets the requirement"
    EOT
  ]
}

Multiple heredocs in a single task

Each command in the list is independent. You can mix regular strings and heredocs:
task "prepare-release" {
  description = "Build changelog and tag the release"
  commands = [
    "git fetch --tags",
    <<-EOT
      last_tag=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
      if [ -z "$last_tag" ]; then
        echo "No previous tag found, generating full changelog"
        git log --oneline > CHANGELOG.md
      else
        echo "Generating changelog since $last_tag"
        git log "$last_tag"..HEAD --oneline > CHANGELOG.md
      fi
    EOT
    "git tag ${var.version}",
    "git push origin ${var.version}",
  ]
}

Interpolation in heredocs

${} interpolation works inside heredocs:
variable "env" {
  type    = string
  default = "staging"
}

task "deploy" {
  commands = [
    <<-EOT
      echo "Deploying to ${var.env}"
      kubectl config use-context ${var.env}
      kubectl apply -f k8s/${var.env}/
    EOT
  ]
}
To pass a literal ${} to the shell (instead of evaluating it as an Errand expression), escape the dollar sign:
commands = [
  <<-EOT
    for file in $${FILES}; do
      echo "Processing $${file}"
    done
  EOT
]

Notes

  • The content of a heredoc is a single string passed to the shell interpreter. The shell processes it as one script, not line by line.
  • Trailing newlines are preserved. Use chomp() if you need to strip them in an expression context.