# Common workflows

Ready-made Terraform pipelines for Buddy: plan on pull requests, destroy behind an approval, import existing resources, and lint and scan before planning.

## Plan on pull requests

Run Plan, without Apply, on every pull request, so reviewers know what a change does before it's merged.

```yaml
- pipeline: Plan PR
  events:
    - type: PULL_REQUEST
  actions:
    - action: Plan
      type: TERRAFORM_PLAN
      tool: OPENTOFU
      version: 1.12.6
      working_directory: infra
      backend:
        type: ARTIFACT
        artifact: infra-state
        artifact_version: prod
```

The run status is reported to the pull request. Reviewers open the run to see the [resource diff](/docs/terraform/plan-and-apply.md#the-resource-diff). To post the result somewhere else, add an action that sends `$BUDDY_ACTION_TF_PLAN_SUMMARY`, for example to Slack. See [Pull request testing](/docs/pipelines/pipeline-examples/pull-request-testing.md) for how pull request pipelines work.

<Hint type="info">

A plan reads the state but doesn't change it. It still takes the state lock while it runs, so a PR plan and an apply on the same state wait for each other.

</Hint>

## Destroy the infrastructure

Pass `-destroy` to the Plan action. The plan then deletes every resource in the state, and Apply runs it like any other plan. Keep this in a separate, manually triggered pipeline, with an approval that blocks self-approval:

```yaml
- pipeline: Destroy staging
  actions:
    - action: Plan destroy
      type: TERRAFORM_PLAN
      tool: OPENTOFU
      version: 1.12.6
      working_directory: infra
      additional_args: -destroy
      backend:
        type: ARTIFACT
        artifact: infra-state
        artifact_version: staging
    - action: Approve
      type: WAIT_FOR_APPLY
      description: "Destroys: $BUDDY_ACTION_TF_PLAN_DESTROY_RESOURCES"
      prevent_self_approval: true
    - action: Apply
      type: TERRAFORM_APPLY
      tool: OPENTOFU
      version: 1.12.6
      working_directory: infra
      backend:
        type: ARTIFACT
        artifact: infra-state
        artifact_version: staging
```

## Import existing resources

**With an `import` block** (Terraform 1.5 and later, OpenTofu): add the block to your code and run the regular Plan → Apply pipeline. The diff shows the resource being imported.

```hcl
import {
  to = aws_s3_bucket.assets
  id = "my-assets-bucket"
}
```

**With `terraform import`:** run it in the [Terraform CLI action](/docs/terraform/terraform-cli.md#examples).

## Validate before planning

Catch formatting and syntax errors before they reach Plan. Run `fmt` and `validate` in the [Terraform CLI action](/docs/terraform/terraform-cli.md) at the start of the pipeline:

```yaml
- action: Validate
  type: TERRAFORM
  version: 1.5.7
  working_directory: infra
  commands: |-
    terraform fmt -check -recursive
    terraform init -backend=false
    terraform validate
- action: Plan
  type: TERRAFORM_PLAN
  tool: OPENTOFU
  version: 1.12.6
  working_directory: infra
```

`init -backend=false` downloads providers and modules without touching the state. If validation fails, the run stops before Plan.

Linters and security scanners such as tflint, checkov, or trivy can run in their own images in a [Run Docker Image action](/docs/actions/docker/run-docker-image.md).


---
Original source: https://buddy.works/docs/terraform/recipes