Changing things safely
🎯You'll be able to
Read a plan's symbols, spot replacements and deletions before they happen, and use lifecycle settings to change things without downtime or data loss.
🏠The everyday picture
A dentist explains the plan before starting: "this filling we'll repair; this tooth we'll take out and replace with an implant". You'd want to hear "take out" before they start, not after.
📘What it really is
- Plan symbols:
+create;-destroy;~update in place (the resource stays, a setting changes);-/+destroy and then create a replacement;+/-create the replacement first, then destroy the old one;-
lines marked
# forces replacementshow which setting can't be changed in place. -
Many settings can't change in place. For a Docker container, almost any change (image, environment, ports) means a new container. In a cloud, changing a database's storage type or a server's base image may mean replacement too. Replacing a database without a volume or snapshot loses its data.
-
Lifecycle settings change how Terraform replaces things:
create_before_destroy = truestarts the new one before removing the old. For app copies, that means the site keeps serving during a change. Names must then be unique, because both exist for a moment (RouteRani adds a random suffix that changes with each version);prevent_destroy = truemakes any plan that would destroy this resource fail. Useful on production databases;-
ignore_changes = [tags]stops Terraform undoing changes another system makes to listed settings. -
Watch out:
create_before_destroyalso applies to everything that resource depends on. If the API copies useddepends_on = [docker_container.db], Terraform would also try to start a second database before removing the first, which on one volume is dangerous. RouteRani's app copies leave out thatdepends_onon purpose and retry the database connection instead. -
Replacing on purpose:
terraform apply -replace=docker_container.dbreplaces a resource even though nothing changed, for example to recover a broken one. -
Wait for health: the Docker provider's
wait = truemakes Terraform wait until the container's health check passes. If it doesn't pass in time (wait_timeout), the apply stops with an error, and withcreate_before_destroythe old copies are still running.
📝A worked example
Input: in the finished kit, run terraform plan -var app_version=1.0.1 (after building routerani:1.0.1).
Expected output: the app copies show +/- (create replacement and then destroy), with name and image marked # forces replacement.
terraform apply -var app_version=1.0.1 starts two new copies, waits for them to be healthy, then removes the old ones. In the starter
(no create_before_destroy), the same change shows -/+: the only copy is removed first, so requests fail while the new one starts.
🌍Where it's used
- Zero-downtime releases of servers or containers managed by Terraform (CD8).
- Protecting data:
prevent_destroyon production databases and storage buckets. - Shared resources:
ignore_changeson settings an autoscaler or another team manages.
📝Case scenario
An e-commerce engineer renamed a database resource in Terraform to tidy the code. The plan showed -/+ on the production database, but it
was one line among 40 and they didn't notice. The apply deleted the database; restoring the night's snapshot took four hours and lost the
morning's orders. The team added prevent_destroy, a pipeline step that fails any plan deleting a database, and the moved block for
renames (CD4).
🖱️Try it
Add lifecycle { prevent_destroy = true } to docker_container.db in your copy and run terraform plan -destroy. Remove it again
afterwards. Success: Terraform refuses with an error naming the resource, and you've seen how the guard works.
⚠️Common mistakes
- Skimming plans. Sign: "I didn't see the replace". Fix: search each plan for
destroyandreplace; have pipelines fail on unexpected deletions. create_before_destroywith fixed names. Sign: "name already in use" errors. Fix: include something unique (a version or random suffix) in the name.- Replacing a database with no volume or snapshot. Sign: empty tables after a "small" change. Fix: keep data on volumes or managed storage, and protect it.
🛠️For your project
Project 1 test 9 replaces the database and checks bookings survive, and Project 2 relies on create_before_destroy for deploys with no
failed requests.
✅Quick check
What's the difference between -/+ and +/- in a plan?
Show the answer
-/+ destroys first, then creates; +/- creates the replacement first, then destroys the old one.
What does prevent_destroy do?
Show the answer
Makes any plan that would destroy that resource fail.
