In Terraform, what does `create_before_destroy = true` in a resource's lifecycle block change about how that resource is replaced, and what must be true of the resource for it to work?
answer
- about ordering, not about updates
- new one first, old one after
- two objects exist at once
- fixed names collide — use a prefix
- contagious through the dependency chain
basics
~20 sBy default Terraform destroys a resource before creating its replacement. Setting create_before_destroy = true inverts that order — the new object is created first, then the old one is destroyed — so it only works when both objects can briefly exist at once.
solid answer
~50 sWhen a change touches an attribute the provider cannot update in place, Terraform plans a replacement: a destroy followed by a create. `create_before_destroy = true` in the resource's `lifecycle` block flips that order, so the replacement is created, everything that depends on it is re-pointed at the new object, and only then is the old one destroyed. That removes the outage window between the two operations. The catch is that two copies exist simultaneously, so the resource must tolerate it: anything with a unique name has to use a generated name instead of a fixed one — `name_prefix` rather than `name` on resources like `aws_security_group` — and you need headroom in quotas, ports and cost for the overlap. It also effectively propagates through the dependency chain, and a chain where only some resources use it is the classic source of `Cycle:` errors.
code
hcl · 15 linesresource "aws_security_group" "app" {
name_prefix = "app-"
vpc_id = var.vpc_id
ingress {
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["10.0.0.0/8"]
}
lifecycle {
create_before_destroy = true
}
}go deeper
Know that Terraform's default replacement order is destroy-then-create, and that this flag reverses it so the new object exists before the old one goes away.
Explain that it only affects replacements, that the resource must tolerate two copies existing, and that a fixed name has to become a generated one via name_prefix.
Show the operational reasoning: which changes force replacement, the outage window you are removing, the quota and cost of the overlap, and how you resolve the cycle errors that appear when only part of a chain uses it.
Own the estate-wide decision — whether shared modules bake create_before_destroy in by default, what naming discipline that imposes on every consumer, and when an overlap is unacceptable so the change must be staged instead.
## What "replacement" means Terraform compares your configuration with the object recorded in state. Most differences are applied in place with an update call to the provider API. Some attributes cannot be changed on a live object at all — the provider marks them as forcing replacement, and the plan shows the resource being destroyed and created rather than updated. `create_before_destroy` controls **only the order of those two operations**. It never converts a replacement into an in-place update, and it never prevents a replacement. ## The default order: destroy, then create Without the setting, Terraform destroys the existing object first and then creates the new one. That is the safe default for anything with a hard uniqueness constraint, because the old object's name, port or address is released before the new one asks for it. The price is a window in which the thing does not exist. If the create then fails — a quota error, an invalid AMI, an API outage — you are left with neither the old nor the new object, and the state file records only the destroy. ## What the flag changes ```hcl lifecycle { create_before_destroy = true } ``` With this set, Terraform creates the replacement first, updates every resource that referenced the old object so it points at the new one, and destroys the old object last. For a security group attached to running instances, a launch template feeding an autoscaling group, or a TLS certificate referenced by a listener, this is the difference between a rolling change and a brief outage. It is the standard way to get zero-downtime replacement out of a plain `terraform apply`. ## What the resource has to tolerate Because both objects exist at the same time, anything the provider or the cloud API treats as unique becomes a collision: - **Names.** A hardcoded `name = "app-sg"` makes the create fail with a duplicate-name error, and the apply stops with the old object still in place. The fix is to let the provider generate the name from a prefix — most AWS resources that have a `name` also accept `name_prefix` — or to omit the name entirely where the provider allows it. - **Quota and cost.** For the length of the apply you are paying for, and consuming quota for, two of everything. On large `count`/`for_each` fan-outs that doubling is not trivial. - **Genuinely single-instance objects.** Some things simply cannot exist twice: a fixed elastic IP association, a bucket name, an attachment that the API allows only once. There, create-before-destroy is not available and you have to accept the gap or split the change into two applies. ## Propagation and cycle errors The ordering constraint does not stop at one resource. If A must be created before the old A is destroyed, then anything the old A depends on cannot be destroyed until after the new A exists. Terraform pushes the create-before-destroy ordering through those dependency edges where it can. When it cannot reconcile a chain in which some resources are create-before-destroy and others are destroy-before-create, the plan fails with a `Cycle:` error naming the resources involved. The remedy is to set the flag consistently across the whole chain rather than on a single leaf resource — which is why shared modules that use it tend to use it everywhere. ## How it sits next to the other lifecycle arguments - `prevent_destroy = true` still fires on a replacement, because a replacement contains a destroy. The two together mean "this may not be replaced at all". - `ignore_changes` can stop the replacement from ever being planned, by telling Terraform not to react to the attribute that forces it. - Drift detection is unaffected. `create_before_destroy` does not change what Terraform notices about the real world, only the sequence in which it fixes it. ## Interview framing The answer that lands is: default is destroy-then-create; this flips it for zero-downtime replacement; it forces you to solve naming, usually with `name_prefix`; and it is contagious through the dependency graph, so half-applying it produces cycle errors. Mentioning that it costs double resources during the overlap shows you have actually run it against something large.
- Why do people pair create_before_destroy with name_prefix instead of a fixed name?Because the replacement is created while the original still exists. A fixed `name` means the create hits a duplicate-name error from the API and the apply stops. `name_prefix` asks the provider to generate a unique suffix for each object, so the two can coexist for the few seconds between create and destroy.
- What happens if only one resource in a dependency chain has create_before_destroy set?Terraform tries to propagate the ordering to the resources it depends on. Where it cannot reconcile create-before-destroy with destroy-before-create in the same chain, the plan fails with a `Cycle:` error listing the resources. The fix is to set the flag consistently across the chain rather than on one resource.
- Does create_before_destroy help if the change is an in-place update rather than a replacement?No. It only orders the destroy and create of a replacement. If the provider can update the object in place, there is no destroy to reorder and the setting has no effect at all. Check the plan output: it only matters when you see `must be replaced` or `forces replacement`.
It is moving into the new flat before handing back the keys to the old one: no night on the street, but you pay two rents for the overlap and you cannot use the same address for both.
saying these in an interview costs you the question
- Says create_before_destroy stops the resource being replaced
- Uses it while keeping a hardcoded unique name
- Thinks it applies to ordinary in-place updates too
- Forgets both objects exist at once, doubling quota and cost
- Sets it on one resource and is surprised by a cycle error