how/state
Declarative blocks for renaming, dropping, and pulling in resources. What they give you beyond the CLI, which Terraform versions added them, and why they live in git.
The imperative commands state mv, state rm, and import solve
specific problems (see tf-state-mv-rm-import), but they share one
issue: they are not reproducible.
That is why Terraform gradually gained declarative counterparts:
moved block, since Terraform 1.1 (December 2021).import block, since Terraform 1.5 (June 2023).removed block, since Terraform 1.7 (January 2024).All three are written directly in HCL, land in git, and run through
terraform apply as part of a normal plan. Press ▶.
One resource in HCL, one entry in state, one bucket in the cloud.
resource "aws_s3_bucket" "old" {bucket = "linuxlab-3f4a"
}
The same starting setup as in tf-state-mv-rm-import. Now you will change it declaratively, through blocks in HCL rather than through the CLI.
recap
When blocks beat the CLI:
dev/staging/prod). One block runs in all of them.When the CLI is still the right tool:
terraform state list, terraform state show <addr>.state replace-provider).Lifecycle of moved/removed/import blocks:
All three are transient. Once a block has run during apply, you can delete it from HCL: the state is already changed, and running the block again does nothing. In practice teams often keep them for a couple of sprints in case of a rollback, then remove them.
If you forget to delete a moved block and then delete the target
resource (aws_s3_bucket.primary), Terraform starts to complain: "the
moved block references an address that does not exist." That is a sign
the block is stale and it is time to clean up.
Next: tf-state-anatomy on how state is built, tf-drift on what happens between applies.