terraform apply
terraform apply executes the changes needed to bring your infrastructure to the desired state. It’s the command that actually creates, modifies, or destroys real cloud resources. Understanding how to use it safely — especially in production — is one of the most critical Terraform skills.
Basic Usage
terraform applyBy default, apply generates a fresh plan and prompts for confirmation:
Plan: 2 to add, 1 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: yesThe Safe Production Pattern: Plan File
The most reliable production workflow separates planning from applying:
# Step 1: Generate a plan and save itterraform plan -out=tfplan
# Step 2: Review the plan (show it or post it to a PR)terraform show tfplan
# Step 3: Apply exactly that plan — no re-planning, no surprisesterraform apply tfplanWhen you apply a saved plan file:
- Terraform does NOT re-plan
- Terraform does NOT show the confirmation prompt
- What was reviewed is exactly what executes
This is essential for: change approvals, audit requirements, and preventing race conditions where another change lands between your plan and apply.
Key Flags
# Skip confirmation prompt (use in CI/CD, never manually on production)terraform apply -auto-approve
# Apply only specific resource(s) — useful for debuggingterraform apply -target=aws_instance.webterraform apply -target=module.vpc.aws_subnet.public
# Override variables at apply timeterraform apply -var="instance_count=5"terraform apply -var-file="prod.tfvars"
# Control parallelism (default: 10 concurrent operations)terraform apply -parallelism=20
# Skip state refresh before applyingterraform apply -refresh=false
# Non-interactive mode for CIterraform apply -input=false -auto-approve
# Compact output for large appliesterraform apply -compact-warningsApply Output Explained
aws_vpc.main: Creating...aws_vpc.main: Creation complete after 2s [id=vpc-0abc123def456789]aws_security_group.web: Creating...aws_subnet.public["a"]: Creating...aws_subnet.public["b"]: Creating... ← runs in parallel with ["a"]aws_security_group.web: Creation complete after 3s [id=sg-0abc123]aws_subnet.public["a"]: Creation complete after 5s [id=subnet-0abc]aws_subnet.public["b"]: Creation complete after 5s [id=subnet-0def]aws_instance.app: Creating...aws_instance.app: Still creating... [10s elapsed]aws_instance.app: Creation complete after 18s [id=i-0abc123def456789]
Apply complete! Resources: 5 added, 0 changed, 0 destroyed.
Outputs:public_ip = "54.123.45.67"Resources that don’t depend on each other are created in parallel — notice both subnets created simultaneously. Terraform automatically determines the execution order from the dependency graph.
Apply Behaviors by Resource Change Type
| Change Type | Apply Behavior | Impact |
|---|---|---|
| New resource | Creates resource | Safe |
| Attribute update (in-place) | Modifies resource | Possible brief disruption |
| Attribute update (forces replace) | Destroys then creates | Potential downtime |
| Resource removed from config | Destroys resource | Data loss if not backed up |
| No change | No action taken | Zero impact |
Handling apply Failures
When apply fails partway through, Terraform updates state with successfully-created resources and then stops:
aws_vpc.main: Creation complete after 2s [id=vpc-0abc123]aws_instance.app: Creating...aws_instance.app: Still creating... [10s elapsed]╷│ Error: creating EC2 Instance: InsufficientInstanceCapacity│ There is no Spot capacity available in the specified availability zone.╵
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.After fixing the issue, re-run terraform apply — Terraform knows which resources were already created (from state) and won’t duplicate them.
CI/CD Apply Pattern
# GitHub Actions — apply only on merge to main- name: Terraform Apply if: github.ref == 'refs/heads/main' && github.event_name == 'push' run: | terraform apply -input=false -auto-approve tfplan env: AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}Principle of least surprise: in automated pipelines, always apply a saved plan file from the PR’s plan step. Never run a fresh apply -auto-approve in production — the plan could be different from what the team reviewed.
Apply with Workspaces
# Ensure you're in the right workspace before applyingterraform workspace select productionterraform workspace show # Verify: "production"terraform apply -var-file="environments/production.tfvars"What Happens to State After Apply
After a successful apply:
- State file is updated with the new resource IDs and attributes
- If using a remote backend (S3, Terraform Cloud), state is written there
- State lock is released
After a failed apply:
- State reflects only the successfully-created resources
- Terraform will detect partially-created infrastructure on next plan