Skip to content
Infrastructure as Code iac workflow 5 min read

terraform apply

terraform apply is the command that actually changes your infrastructure. It takes the diff that plan describes — resources to create, update, or destroy — and executes the corresponding provider API calls, then records the new reality in state. Because it mutates real cloud resources, apply defaults to an interactive confirmation step: it shows you the plan and waits for you to type yes before touching anything. Understanding that confirmation flow, how to apply a saved plan, and what the output means is the difference between a safe rollout and an outage.

The default interactive apply

Run with no arguments, apply first generates a fresh plan, prints it, and pauses for approval. This is the safest mode for day-to-day work because you review the exact changes immediately before they happen.

terraform apply

Output:

Terraform used the selected providers to generate the following execution
plan. Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # aws_s3_bucket.assets will be created
  + resource "aws_s3_bucket" "assets" {
      + bucket = "acme-assets-prod"
      + id     = (known after apply)
      + arn    = (known after apply)
    }

Plan: 1 to add, 0 to change, 0 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

aws_s3_bucket.assets: Creating...
aws_s3_bucket.assets: Creation complete after 2s [id=acme-assets-prod]

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

Only the literal string yes approves — y, Y, or an empty line all abort with no changes made. The configuration below produced that plan:

resource "aws_s3_bucket" "assets" {
  bucket = "acme-assets-prod"
}

OpenTofu users run tofu apply; the flags, approval flow, and output format are identical, so everything on this page applies to both tools.

Applying a saved plan

The plan that an interactive apply shows you is regenerated at apply time, so in theory the world could have changed between your review and your yes. To eliminate that gap, save a plan to a file and apply exactly it. When you pass a saved plan file, apply skips the prompt entirely — the file is itself the approval.

terraform plan -out=tfplan
terraform apply tfplan

Output:

aws_s3_bucket.assets: Creating...
aws_s3_bucket.assets: Creation complete after 2s [id=acme-assets-prod]

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

This plan-then-apply split is the standard pattern in CI/CD pipelines: a plan stage produces the artifact, a human (or policy check) reviews it, and a separate apply stage consumes the exact same artifact. There is no ambiguity about what will run.

Skipping approval with -auto-approve

-auto-approve tells apply to proceed without the interactive prompt. It generates a plan and runs it immediately.

terraform apply -auto-approve

This is convenient but removes your last safety net, so it is only appropriate in specific contexts.

ScenarioSafe to auto-approve?Why
Local development against throwaway resourcesYesMistakes are cheap and reversible
CI applying a previously reviewed saved planUse the plan file insteadThe saved plan already encodes approval; no flag needed
CI with no prior plan reviewNoNothing reviews the diff before it executes
Production from a developer laptopNoOne typo can destroy live infrastructure

Prefer apply tfplan over apply -auto-approve in pipelines. Applying a saved plan guarantees the executed changes are byte-for-byte what was reviewed, whereas -auto-approve re-plans against live state that may have drifted since review.

Useful apply options

FlagEffect
-auto-approveSkip the interactive yes prompt
-input=falseDisable all prompts; fail rather than ask (use in CI)
-parallelism=nLimit concurrent resource operations (default 10)
-target=ADDRApply only the given resource and its dependencies
-var / -var-fileSupply input variable values
-replace=ADDRForce-recreate a specific resource on this apply
-refresh=falseSkip refreshing state before planning (faster, riskier)

Partial failures

Provider API calls can fail mid-apply — a quota limit, an invalid argument, a transient network error. Terraform applies resources according to the dependency graph, so a failure stops dependent work but does not roll back resources that already succeeded. Anything created before the error is real and is recorded in state.

aws_vpc.main: Creation complete after 3s [id=vpc-0a1b2c3d]
aws_subnet.public: Creating...

│ Error: creating EC2 Subnet: InvalidParameterValue: CIDR 10.0.0.0/25 is
│ not a valid subnet for VPC vpc-0a1b2c3d

│   with aws_subnet.public,
│   on network.tf line 12, in resource "aws_subnet" "public":
│   12: resource "aws_subnet" "public" {


Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

Here the VPC was created and saved; only the subnet failed. Terraform does not undo the VPC. Fix the configuration and re-run apply — because state already knows the VPC exists, the next plan shows only the remaining subnet, making apply naturally resumable. This is why apply is idempotent: re-running it converges toward the desired state rather than duplicating work.

Reading apply output

Every apply ends with a one-line summary you should read carefully:

Apply complete! Resources: 3 added, 1 changed, 2 destroyed.

The three counts map directly to the +, ~, and - symbols from the plan. A destroyed count you did not expect is a red flag — it means something forced replacement or removal. During execution, each resource logs Creating..., Modifying..., or Destroying... lines with elapsed timers, and finally Outputs: prints any defined output values once everything settles.

Best Practices

  • In pipelines, always apply a saved plan file produced by an earlier reviewed plan rather than re-planning at apply time.
  • Reserve -auto-approve for ephemeral or local environments; never wire it to production from a workstation.
  • Add -input=false in automation so a missing variable fails the job instead of hanging on a prompt.
  • Read the final summary line — an unexpected destroyed count means stop and investigate before celebrating.
  • Treat partial failures as resumable: fix the root cause and re-apply rather than manually cleaning up created resources.
  • Lower -parallelism only when a provider rate-limits you; the default of 10 is right for most cases.
  • Keep state locking enabled so two simultaneous applies cannot corrupt your state.
Last updated June 14, 2026
Was this helpful?