skip to content

Remote Backends

Local state on a laptop stops working the moment a second engineer joins. I need to name the common remote backends and describe migrating an existing project onto one without losing resources.

part ofTerraformoverview, primer and where to startread it →
on this pageshow

questions

5

Terraform writes terraform.tfstate to the local working directory by default. What breaks once a second engineer starts running applies on the same project, and what does moving to a remote backend actually fix?

level: juniorimportance: must knowfreq 82%

answer

  1. one laptop, one private record
  2. second engineer, divergent pictures
  3. Git has no lock
  4. shared, versioned, lockable object
  5. backend block inside terraform block

basics

~20 s

A remote backend keeps Terraform state in shared, durable storage such as an S3 bucket instead of one laptop's disk. Every engineer and CI job then reads and writes the same state, so runs cannot silently diverge, duplicate resources, or destroy each other's work.

solid answer

~50 s

By default Terraform records state in a local `terraform.tfstate` file next to the configuration. That is fine for one person, and it fails the moment a second one appears: each laptop has its own partial record, so my plan does not know about the resources you created, and an apply can duplicate them or propose destroying things it has no record of. Local state also has no locking, no durability if the laptop dies, and no way for CI to run at all. Committing the file to Git is not a fix — JSON state merge conflicts are effectively unresolvable, there is still no lock, and the file contains secrets in plaintext. A remote backend (`s3`, `gcs`, `azurerm`, or HCP Terraform via the `cloud` block) makes the state a single shared, versioned, lockable object that every run reads before planning and writes after applying.

go deeper

for a junior

Know that Terraform defaults to a local terraform.tfstate file, that a team needs it in shared storage instead, and be able to name S3, GCS or Azure blob storage as where it goes.

for a middle

Explain the concrete failures — divergent state, no locking, no durability, CI cannot run — and why committing state to Git fixes none of them because JSON merges and plaintext secrets make it worse.

for a senior

Show the operational setup you would insist on: versioning enabled on the state bucket, encryption at rest, an access policy that treats state as secret material, and a single agreed place every pipeline reads it from.

for a principal

Own the estate-wide decision: which backend the organisation standardises on, how state buckets are provisioned and governed before any team writes Terraform, and who is allowed to read state given it is equivalent to reading production secrets.

## What state is doing in the first place Terraform records, for every resource in your configuration, the real-world object it corresponds to — the AWS instance ID, the bucket ARN, the last-seen attribute values. Without that record Terraform cannot tell "this resource already exists and matches" from "this resource does not exist yet", so it plans a create. State is the memory between runs, which is exactly why *where it lives* determines who can safely run Terraform. ## What local state actually is With no `backend` block configured, Terraform uses the `local` backend: a `terraform.tfstate` file in the working directory, plus a `terraform.tfstate.backup` holding the previous version. It is a plain JSON file on one machine's disk. Nothing about it is shared, replicated, or coordinated. ## The four failures on a team **Divergence.** You create a load balancer; my copy of the state has never heard of it. My next plan is computed against an incomplete picture. Depending on the configuration I either create a second one or, if the config no longer mentions something my state does remember, propose destroying it. **No mutual exclusion.** Two applies running at the same time both read state, both mutate infrastructure, and the second write clobbers the first. The result is real resources with no state entry — orphans that Terraform will happily try to create again. **Durability.** The authoritative record of your production estate is on a laptop that can be lost, reimaged, or have its working directory deleted. There is no backup you did not make yourself. **No automation.** A CI job starts from a fresh checkout with no state file, so it plans to create the entire estate from scratch. Pipelines are impossible until state is somewhere both humans and runners can reach. ## Why "just commit it to Git" is not the answer It is the tempting first idea and it fails on three counts. Git has no locking, so two people can still apply concurrently and only discover it at push time — after the infrastructure has already changed. State is machine-generated JSON with serial numbers and embedded attribute values; a merge conflict in it cannot be resolved by hand in any trustworthy way. And state stores resource attributes verbatim, including generated passwords and keys, so committing it puts secrets into the repository history permanently. ## What a remote backend changes A backend is declared inside the `terraform` block and tells Terraform where to persist state: ```hcl terraform { backend "s3" { bucket = "acme-tfstate-prod" key = "platform/network/terraform.tfstate" region = "eu-west-1" } } ``` After `terraform init`, every plan and apply fetches the state object from that bucket first and writes it back at the end. The file never lives permanently on the workstation. The commonly used ones are `s3` on AWS, `gcs` on Google Cloud, `azurerm` on Azure (blob storage), and HCP Terraform — which is configured with a `cloud` block rather than a `backend` block, and additionally offers running the plan and apply on HashiCorp's infrastructure instead of yours. The shared object also gives you the two things local state cannot: a lock, so a second concurrent run waits or fails rather than racing, and object versioning, so a corrupted or truncated state can be rolled back to a previous version. Enabling versioning on the state bucket is not optional in practice — it is the only undo you get. ## What a remote backend does *not* fix State is still plaintext JSON containing whatever attributes the providers returned, so the bucket needs encryption at rest and a tight access policy: read access to state is effectively read access to your secrets. And the CLI still runs wherever you invoke it — with `s3`, `gcs` or `azurerm`, only the *storage* is remote, not the execution. Credentials, provider plugins and the plan itself are still local. ## How to say it in an interview "Local state is single-player. The second engineer turns it into two divergent, unlocked, undurable records of production. A remote backend makes state one shared, locked, versioned object that both humans and CI read before they plan."

  • If both engineers keep local state, what does the damage actually look like the first time it happens?
    Typically duplicate resources or a surprise destroy. My state has no record of the subnet you created, so either the config makes me create a second one, or my state still remembers a resource you already removed from the code and I plan to destroy it. Both are discovered after apply, because each plan looked perfectly reasonable against its own partial state.
  • Does using a remote backend mean Terraform runs remotely?
    No, not for `s3`, `gcs` or `azurerm` — only the state is remote. The CLI still executes on your machine or your CI runner, using your local credentials and downloaded providers. Remote *execution* is a separate feature of HCP Terraform, configured with the `cloud` block, where the plan and apply run on HashiCorp's workers.
  • Should the state file still be in .gitignore once you use a remote backend?
    Yes. Terraform still writes local artefacts — the `.terraform` directory, and a `terraform.tfstate` left over from before migration — and plan files also contain state data. The standard ignore set covers `.terraform/`, `*.tfstate`, `*.tfstate.*` and `*.tfplan`, so no state or plan ever reaches the repository.

saying these in an interview costs you the question

  • Says Terraform can rebuild state by scanning the cloud account
  • Proposes committing terraform.tfstate to Git for sharing
  • Thinks a remote backend also runs the apply remotely
  • Claims remote state removes the need to encrypt or restrict it
  • Believes concurrent applies are safe because plan refreshes first

context

open as a page

You inherit a Terraform project managing about 60 live resources whose state is a local terraform.tfstate file. How do you move it onto an S3 backend without destroying or recreating anything?

level: middleimportance: must knowfreq 62%

basics

~20 s

Create the state bucket first with versioning enabled, add a backend "s3" block to the terraform block, then run terraform init -migrate-state to copy the existing state up. Confirm success by running terraform plan and seeing no changes.

open as a page

Why does Terraform reject an input variable inside a backend block, and how do you point the same configuration at a different state bucket per environment given that restriction?

level: middleimportance: should knowfreq 50%

basics

~20 s

Backend settings are read at init, before variables, locals or providers are evaluated, so they must be literal values. The workaround is partial configuration: omit the varying arguments and supply them at init with -backend-config files or key=value flags.

open as a page

A failed pipeline run leaves the Terraform state object in your S3 backend truncated and unusable. How does bucket versioning let you recover, and what do you check after restoring?

level: seniorimportance: should knowfreq 45%

basics

~20 s

S3 bucket versioning keeps every previous copy of the state object, so recovery means listing object versions, identifying the last good one, and restoring it as the current version. Afterwards run terraform plan: unexpected creates mean resources built after that snapshot need importing.

open as a page

When would you choose HCP Terraform's cloud block over a self-managed S3 backend for a team's Terraform state, and what does each choice cost you?

level: principalimportance: nice to knowfreq 33%

basics

~20 s

A self-managed object-storage backend stores state cheaply and keeps everything inside your account, but you build locking, versioning, access control and the pipeline yourself. HCP Terraform provides state, locking, run history, RBAC and optional remote execution as a product, at per-resource cost and outside your network.

open as a page