Import manually-created resources before the next apply
The best way to avoid this entirely is to define resources in Terraform from the start — terraform apply will create them automatically and they’ll always be tracked. See reserving a static IP via Terraform for a concrete example.
If you create a resource manually (e.g. in the GCP Console) and Terraform doesn’t know about it, you have two options: destroy the manual resource and let Terraform recreate it, or import the existing one into Terraform state.
Destroying causes downtime and changes identifiers (IP addresses, resource IDs). Importing preserves everything.
# zsh requires quoting import IDs that contain slashes
terraform import google_compute_address.static_ip \
'projects/my-project/regions/us-east1/addresses/my-static-ip'The import ID format is provider-specific — check the Terraform registry docs for the resource you’re importing. After importing, run terraform plan to confirm Terraform sees no diff between your config and the imported state.
Warning
An untracked resource is invisible to Terraform. It will either be ignored (silent drift between config and reality) or destroyed and recreated on the next apply that touches it.
Tip
Rule — Any infrastructure created manually must be imported into Terraform state before the next
terraform apply.
Read plan output for # forces replacement before applying
Certain field changes cause Terraform to destroy the existing resource and create a new one — not update it in place. Terraform marks these in plan output with # forces replacement:
# google_compute_instance.vm must be replaced
+/- resource "google_compute_instance" "vm" {
~ metadata_startup_script = "..." -> "..." # forces replacement
}
The +/- symbol on the resource block means destroy + create, not update. If you see this on a production resource, stop and verify:
- Is your data backed up outside the VM (GCS, Cloud SQL)?
- Is your IP static (
google_compute_address)? If not, it will change. - Is the replacement safe to do right now?
Warning
# forces replacementmeans the old resource is deleted first. There is no in-place swap, and there is no rollback once the destroy step completes.
Tip
Rule — Read every line of
terraform planbefore applying on a production resource. Neverterraform applya plan you haven’t fully read.
See also
- gcp-vm-terraform-gotchas — which GCE fields trigger force replacement and why
- terraform-variables — variables.tf / tfvars / var.<name>