# dflook/terraform-github-actions: Terraform and OpenTofu steps for CI

> This repository is a suite of GitHub Actions that wrap Terraform and OpenTofu tasks, from plan and apply to formatting checks and drift detection. It suits teams that want plan review through pull requests and a repeatable apply path, and it does not suit teams that need a general purpose CI script or a private registry of their own actions.

**dflook/terraform-github-actions** — GitHub actions for Terraform and OpenTofu

- Repository: https://github.com/dflook/terraform-github-actions
- Stars: 992 · Forks: 175
- Language: Python
- License: not declared
- Published: 2026-10-20 · Updated: 2026-10-20 · Language: en
- Canonical page: https://hysenlabs.com/projects/dflook-terraform-github-actions

## One action per Terraform command, mirrored for OpenTofu

The structure of this repository is a directory per action, and the list of those directories is the clearest description of what the suite covers. Alongside the Terraform named actions there is a matching `tofu-` directory for every one of them, so the same capability exists for both tools: `terraform-plan` sits next to `tofu-plan`, `terraform-apply` next to `tofu-apply`, and the same pairing continues through output, remote state, validate, fmt, fmt-check, check, new-workspace, destroy-workspace, destroy, version, unlock-state, test and refresh. Fifteen capabilities, twice over. The split is not cosmetic. Terraform and OpenTofu are separate binaries with separate version lines, and an action that shells out to one cannot be reused for the other, so maintaining a parallel set of directories is the honest way to support both. The consequence for a user is that you pick a family once and stay inside it, since a workflow that mixes `dflook/terraform-plan` with `dflook/tofu-apply` is combining two different tools. The primary language of the repository is Python, and each action directory carries its own documentation, which the top level `docs/` and `docs-gen/` directories appear to collect.

## Plan on the pull request, apply on the merge

The core workflow pattern in the documentation is a two file split, and the design logic is simple enough to copy. A plan workflow runs when a pull request is opened or updated, generates a plan, and attaches it to the pull request as a comment for a human to read. A separate apply workflow runs on a push to the main branch and applies the change. The example plan job below is the job section of that first workflow file, and it shows the two inputs the action exposes: the `path` of the configuration directory, and a `GITHUB_TOKEN` from the environment that the workflow grants through `pull-requests: write` so the plan can be written back to the pull request.

```yaml
  jobs:
    plan:
      runs-on: ubuntu-latest
      name: Create a plan for an example terraform configuration
      env:
        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
      steps:
        - name: Checkout
          uses: actions/checkout@v4

        - name: terraform plan
          uses: dflook/terraform-plan@v2
          with:
            path: my-terraform-config
```

A comment on the pull request is a reviewable artefact but a weak one, since it is not a diff in the usual sense. The documentation notes that branch protection can be used to require human review before the merge that triggers apply, and points at the `dflook/terraform-apply` action for the details of that setup. That combination, plan as a comment plus branch protection on the target branch, is the part worth getting right.

## The documented examples still reference the v2 tags

The action directories and the example workflows point at different versions of the same suite. The example workflows in the documentation use `dflook/terraform-plan@v2`, `dflook/terraform-apply@v2`, `dflook/terraform-validate@v2`, `dflook/terraform-fmt-check@v2` and `dflook/terraform-check@v2`, while the published release list for this repository shows v3.0.0 on 2026-07-18, v3.0.1 on 2026-09-03 and v3.1.0 on 2026-09-10. Anyone copying an example straight out of the documentation therefore starts on the previous major line, not the newest one. This is not a warning about breakage, since the repository does not describe what changed in the v3 line, but it is a real difference between what the documentation shows and what the project currently publishes. The `example_workflows/` directory at the top level of the repository is the place to check for the versions the author currently recommends, and the `CHANGELOG.md` at the root is where the release history is recorded. Pinning a major tag rather than a commit hash is also worth a thought, since a tag can move.

## Fmt check and validate as a separate lint job

The linting example runs on every push to a branch that is not the main branch, and it does two different things in two separate jobs. The validate job confirms the configuration is valid, and the fmt-check job confirms the files are in the canonical format, which the documentation describes as extra strictness on top of validation. Running them as two jobs rather than one means a formatting failure does not hide a validation failure, because the two results appear separately in the checks list. The fmt-check job of that example is shown below, trimmed to the job itself.

```yaml
  fmt-check:
    runs-on: ubuntu-latest
    name: Check formatting of terraform files
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: terraform fmt
        uses: dflook/terraform-fmt-check@v2
        with:
          path: my-terraform-config
```

The `path` input appears in every one of these steps, and it points at a directory of configuration rather than at a single file, so the action is aimed at a repository layout where one directory holds the whole configuration set. A repository that keeps Terraform spread across many directories needs one step per directory, or a wrapper, and the documentation does not describe a way to point one action at several roots at once.

## Drift detection on a morning schedule

The check action is presented as a scheduled job that compares the recorded state with the configuration and fails the workflow when anything unexpected is found, which the documentation frames as catching manual or misapplied changes before they become a problem. The drift example runs on a schedule with a cron entry, and the job section is reproduced here.

```yaml
  jobs:
    check_drift:
      runs-on: ubuntu-latest
      name: Check for drift of example terraform configuration
      steps:
        - name: Checkout
          uses: actions/checkout@v4

        - name: Check for drift
          uses: dflook/terraform-check@v2
          with:
            path: my-terraform-config
```

Two things follow from the shape of this job. It needs credentials to read the remote state, and the example does not show where those come from, unlike the plan and apply jobs which set `GITHUB_TOKEN` in the environment. The `dflook/terraform-remote-state` and `dflook/terraform-unlock-state` actions exist to cover parts of that gap, and their own documentation is the reference for how a backend is configured for the runner. The other point is that drift checks need a read only credential in practice, and the documentation does not spell out the permission model, so a team should check the remote state action documentation before pointing a scheduled job at a production backend.

## The action set ends where general purpose CI begins

The suite covers the Terraform task list, and it stops there. There is no cache action, no artifact upload, no matrix builder, no generic shell runner, and no way to run a custom script through these actions, so anything outside the command list in the top level table has to be assembled from the standard GitHub actions or written by you. The `terraform-test` action is the closest thing to a general facility, since it runs the test files that live in a configuration directory. Two other entries show where the awkward parts of infrastructure work are concentrated. Workspace management has its own actions for creating and destroying a workspace, which suggests that the author expected workspace churn to be a common operation rather than something to avoid. And `terraform-destroy` is present as a first class action, next to `terraform-apply`, which tells you the destructive path is a supported and documented route in this suite rather than something users are expected to improvise. Whether that is reassuring depends on how your branch protection and approvals are configured, since the same action set that applies changes can also tear down an environment.

## Licence terms are not stated in the project files

The top level listing of the repository contains directories, documentation, tests and configuration, but no licence file, and the project page carries no licence identifier. That is unusual for a widely copied action suite, and it matters in practice. GitHub Actions from a third party are executed inside your own workflow, and the terms under which that code is offered determine what you can do with it, whether you can vendor it, and whether you can modify it. A repository with no stated licence leaves that question open, so the safe reading is that the code is not available for reuse beyond the package publishing arrangement the author provides. If your organisation has a legal review step, this is the item to raise, and it is more significant here than the fact that the suite is written in Python and would be easy to fork, because easy to fork and permitted to fork are different things. The `tests/` directory in the repository suggests the actions are covered by their own test suite, which reduces the risk of a behavioural surprise but says nothing about licensing.

## Conclusion

Adopt this suite if your infrastructure already lives in Terraform or OpenTofu and you want plan review, formatting checks and drift detection to run as reusable workflow steps without maintaining a custom runner image. Do not adopt it as a general CI toolkit, since the actions are narrow wrappers around the two tools, and do not adopt it without checking where your state backend credentials live, because the remote state and unlock actions exist precisely because that part is hard to do safely. Before the first run, verify the version tag you reference, confirm the `path` input points at the right configuration directory, and decide whether the plan comment written to a pull request is acceptable to your reviewers. The last push was on 2026-09-10 and the newest published release is v3.1.0 from the same day, so the project is being worked on.

## FAQ

### How do I run a Terraform plan on a pull request with dflook/terraform-github-actions?

Add a step that uses `dflook/terraform-plan` to a workflow that runs on `pull_request`, and give it the `path` of your configuration directory. The plan is written back to the pull request as a comment, which needs a `GITHUB_TOKEN` in the job environment and `pull-requests: write` in the workflow permissions.

### Which actions does the suite provide for OpenTofu?

A parallel set of `tofu-` actions mirrors the Terraform ones, including `tofu-plan`, `tofu-apply`, `tofu-output`, `tofu-remote-state`, `tofu-validate`, `tofu-fmt`, `tofu-fmt-check`, `tofu-check`, `tofu-new-workspace`, `tofu-destroy-workspace`, `tofu-destroy`, `tofu-version`, `tofu-unlock-state`, `tofu-test` and `tofu-refresh`.

### Can these actions detect drift in infrastructure that was changed by hand?

Yes, the check action is documented as comparing state against the configuration and failing the workflow on unexpected changes, and the example runs it on a schedule with a cron entry. The example does not show where the state credentials come from, so consult the `dflook/terraform-remote-state` documentation before running it against a production backend.

### What version should I reference in a workflow file?

The documented examples use the v2 tags, while the published releases include v3.0.0, v3.0.1 and v3.1.0. The `example_workflows/` directory and the `CHANGELOG.md` at the repository root are the places to check for the versions currently recommended.

## Sources

- [dflook/terraform-github-actions on GitHub](https://github.com/dflook/terraform-github-actions)
- [Issues](https://github.com/dflook/terraform-github-actions/issues)
- [README](https://github.com/dflook/terraform-github-actions/blob/main/README.md)
- [Releases](https://github.com/dflook/terraform-github-actions/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/dflook-terraform-github-actions
