tfaction is a set of GitHub Actions for running Terraform or OpenTofu on GitHub Actions.
It provides a GitHub Flow where terraform plan runs on pull requests and terraform apply
runs when the pull request is merged. Since v2 it is a single JavaScript Action whose feature
is selected through the action input. It is configured by a repository-wide
tfaction-root.yaml and a per-root-module tfaction.yaml.
Don't read every reference file. Read only the one that matches the task.
Gotchas
- tfaction v2 is a single action. Every feature is selected via the
actioninput onsuzuki-shunsuke/tfaction, so v1 code that calls separate actions such assuzuki-shunsuke/tfaction/setupdoes not work. See Actions for the validactionvalues. - A setting can appear in five places, and the effective value is not "the most specific file wins" alone. From highest to lowest:
tfaction.yamlper-job-type block,tfaction.yamltop level,tfaction-root.yamltarget_groups[]per-job-type block,tfaction-root.yamltarget_groups[],tfaction-root.yamltop level. Check Configuration Priority before concluding a setting is being ignored. terraform applyconsumes the plan file produced duringterraform plan. Once an apply fails, that plan file is stale and rerunning the failed workflow run fails again — a new pull request is needed. This is what follow-up PRs automate.list-targetslists only the root modules that were directly changed. A root module that references a module through a relative path outside its own directory is not listed when only that module changes, unless module dependency detection is configured.- The
skip:<target>label andskip_terraform_filesdo not skip anything by themselves.list-targetsonly reports the decision as theskip_terraformfield of each target, and the workflow has to act on it: gate theplanandapplysteps withif: matrix.target.skip_terraform != true, or pass it as theTFACTION_SKIP_TERRAFORMenvironment variable, which makes those actions warn and do nothing. Gate both steps — gating onlyplanleaves no plan file forapplyto download. Never gateupdate-drift-issue; it has to keep running withif: always(). See Skipping terraform plan and apply. - Approvals are dismissed right after
terraform planby default, so reviewers must approve after seeing the plan. This is on unless it is explicitly disabled. - Drift detection is off by default and is enabled per root module.
- Storing plan files in S3 is AWS-only and applies only to the
terraformjob type;tfmigratedoes not use a plan-file artifact. - GitHub pull request labels are limited to 50 characters. A long path from the repository root to a root module can exceed that and make label creation fail; target aliases exist to shorten it.
Getting started
- What is tfaction — to understand what tfaction does and whether it fits a use case.
- Getting Started — to build a first working workflow with the minimum configuration:
tfaction.yaml,tfaction-root.yaml, installing Terraform, and creating a GitHub App. - tfaction v2 is a Single Action — to understand why the workflow calls the same action repeatedly with different
actioninputs. - Monorepo — to manage more than one root module in a repository.
- Workflows — to see which workflow files exist, what each one does, and which ones a given setup actually needs.
- Actions — to look up a specific
actioninput value, its inputs, outputs, and the environment variables shared across actions.
Configuration
- Configuration Priority — to work out which of several definitions of a setting wins.
- JSON Schema for Configuration Files — to get editor validation and completion for
tfaction.yamlandtfaction-root.yaml. - AWS Configuration — to use the AWS provider or the S3 backend, and to set up the IAM role to assume.
- Configuration for Google Cloud — to use the Google Cloud provider or the GCS backend, and to set up Workload Identity.
- Handling Secrets — to pass secrets to
terraform init,plan, andapplyfrom GitHub Secrets or AWS Secrets Manager without exposing them to later workflow steps. - Configuring Target (Aliases) — to shorten the root module paths that appear in pull request comments and labels, especially when a label hits the 50-character limit.
- Configuring Terraform Command Options — to pass extra options to terraform commands via
TF_CLI_ARGSandTF_CLI_ARGS_name. - Configuring tfcmt — to change the pull request comments tfcmt posts, including disabling its labels.
- Using OpenTofu or Terragrunt — to replace the
terraformcommand with a compatible tool.
Features
- Linting and Formatting — to configure what the
testaction runs:terraform fmt,terraform validate, tflint, and other linters. - Safe Apply Using Plan Files — to understand how the plan produced on a pull request is carried over to apply, and why a failed apply cannot simply be rerun.
- Store Plan Files in S3 — to store plan files in S3 instead of GitHub Artifacts (AWS and the
terraformjob type only). - Follow-up PR — to recover from a failed
terraform applyby having tfaction create the follow-up pull request. - Automatic PR Branch Updates — to re-run plan on pull requests touching a root module after it is applied, and to keep pull request branches up to date with the base branch.
- Drift Detection — to detect divergence between code and real infrastructure and track it as a GitHub Issue per root module. Off by default, enabled per root module.
- Module — to manage a module (not a root module) with tfaction by setting
type: modulein itstfaction.yaml. - Trigger Terraform When Dependent Local-path Modules Are Updated — when a root module is not planned after a local-path module it depends on was changed.
- Scaffolding Root Modules and Modules from Templates — to add a workflow that creates new root modules or modules from templates.
- tfmigrate — to run state migrations as code, such as moving resources between states.
- Destroying All Resources in a Root Module — to run plan and apply with
-destroyby settingdestroy: true. - Code Generation with terraform plan -generate-config-out — to generate resource blocks from import blocks in CI and commit the result.
- Auto Apps (Renovate, Dependabot) — to configure how tfaction treats pull requests opened by apps and machine users.
- Secure Commits and PR Creation with CSM Actions — to create commits and pull requests without granting
contents: writeto the workflow'sgithub_token.
Tuning behavior
- Hiding Or Delete Old PR Comments — when old tfcmt comments pile up on a pull request.
- Dismiss approval before plan — to turn off the default dismissal of approvals after plan.
- Disable PR creation — to have tfaction push a commit and branch, and print a GitHub CLI command, instead of opening a pull request itself.
- Notify bot PR events — to get notified when a bot-authored pull request is reviewed, merged, or closed.
- Limiting the Number of Root Modules Changed in a Single PR — to cap how many root modules one pull request may touch. No limit by default.
- Skipping terraform plan and apply — to skip plan and apply for a root module, either because only files that cannot affect the result were changed (
skip_terraform_files, off by default) or because askip:<target>label was added to the pull request, and to see how the workflow has to act on theskip_terraformfield. - Testing Workflow Changes — to run plan, or plan and apply, on chosen directories when a workflow changed but no root module did.
Upgrading to v2
- v2 Upgrade Guide — to migrate from v1. Every v1 user has to make changes.
- v2 Release Note — to see what changed in v2 and why.