# How it works

Two GitHub Actions workflows automate Terraform in your IaC repository:

- one plans changes in pull requests
- another applies automatically when changes are merged

Both workflows are file-based - that is, they only run against stacks that contain changed files. They can also be manually triggered on-demand.

The Terraform automation setup has standardized on two types of environments: `dev` (for non-production) and `prod` (for production). If your environments are called something else internally, you'll still use `dev` and `prod` when configuring Terraform automation.

<!-- prettier-ignore-start -->
!!! tip "Manual trigger"
    Both workflows can be triggered on-demand by issuing a `workflow_dispatch` event on GitHub. The input supports glob wildcards (`*`, `**`), brace expansion (`{a,b}`), and comma- or newline-delimited lists, such as `stacks/**`, `stacks/{dev,prod}/databases` or `stacks/dev/app-*`.
<!-- prettier-ignore-end -->

## Plan workflow

`terraform-pr.yml` in your IaC repository is a thin caller of the [`reusable-terraform-pr`](https://github.com/oslokommune/reusable-terraform-pr){:target="_blank"} reusable workflow. It runs on pull requests that touch IaC files.

- Detects which stacks contain changed files and runs `terraform plan` against those stacks in **parallel** - unchanged stacks are skipped to keep PRs scoped to what actually changed.
- Posts results as PR comments.

## Apply workflow

`terraform-apply.yml` in your IaC repository is a thin caller of the [`reusable-terraform-apply`](https://github.com/oslokommune/reusable-terraform-apply){:target="_blank"} reusable workflow. It runs automatically on pushes to the default branch, such as `main`.

<!-- prettier-ignore-start -->
!!! warning "Push to apply"
    <!-- "it is" here is the pronoun object of "on" plus the main verb, not the padding "it is" construction the rule targets. -->
    <!-- vale NeedsRewrite.TooWordy = NO -->
    Every push to the default branch automatically runs `terraform apply` against your environments. Your default branch becomes the source of truth for what's applied: everything on it is either already live or on its way out.
    <!-- vale NeedsRewrite.TooWordy = YES -->
<!-- prettier-ignore-end -->

- Detects which stacks contain changed files and runs `terraform apply` against those stacks in a **predefined order**.
- Only one apply runs at a time per stack. A new push won't interrupt an apply that's already running, and if changes pile up while one is in progress, the workflow skips ahead to the most recent one.

The workflow runs up to four sequential jobs, and if a job fails, all later jobs are skipped:

`deploy-dev-core` → `deploy-dev-apps` → `deploy-prod-core` → `deploy-prod-apps`

### Apply order

To determine the order in which stacks apply, the apply workflow groups them into two categories:

- **"Core"** stacks are foundational stacks that other stacks typically depend on (remote state, networking, IAM, databases, `<stack>-data`, and so on). Within an environment, core stacks are applied sequentially in a predefined order so dependencies are maintained.
- **"Apps"** stacks are everything else - typically the stacks that contain individual applications and that depend on core stacks. Within an environment, apps stacks apply in parallel; they are assumed to not depend on each other.

A stack is treated as core if its directory name matches a list of built-in patterns, such as `**/remote-state` or `**/networking`. Teams using standard Golden Path stack names get correct ordering with no configuration.

<!-- prettier-ignore-start -->
!!! tip "Customize apply order"
    You can configure `additional-core-stacks` (appends) or `core-stacks` (replaces) as inputs to the apply workflow to customize the apply order. See the [`determine-stacks`](https://github.com/oslokommune/composite-actions/tree/main/determine-stacks/action.yml){:target="_blank"} composite action - used internally by the reusable workflow - for the full default pattern list.
<!-- prettier-ignore-end -->

## See also

<!-- prettier-ignore -->
- [How CI/CD works for applications](../application/how-cicd-works.md)
- Getting started with CI/CD:
    - [For existing environments](migrate-to-latest-workflows/prepare-infrastructure-repository.md)
    - [For new environments](../initial-setup-of-your-aws-environment/set-up-terraform-workflows.md)
- [Architecture Decision Records (ADRs)](https://github.com/oslokommune/adr/tree/main/team-kj%C3%B8remilj%C3%B8){:target="_blank"}
