TutorialsTerraform › backend.tf

Terraform Tutorial · File 2 of 9

backend.tf

Tells Terraform to store its memory of what it built — its state — in a shared Azure Storage location instead of a file on one person's laptop, so anyone on the team, or GitHub Actions, sees the same up-to-date picture of the infrastructure.

Codey the Sr Developer, standing with a pointer, ready to walk through the guide
Backend type → azurerm Auth method → Microsoft Entra ID Filled in via → backend.hcl (not committed)

Purpose of this file

Configure where Terraform stores its state, using a shared Azure Storage location instead of a local file.

Codey pointing to the left
where the memory lives

Terraform's state file is the single most important thing it manages besides your actual cloud resources — it's the record of what Terraform believes already exists. This file decides where that record lives.

The full file code sample

terraform/backend.tf# Backend location is supplied by the workflow or a local backend.hcl file.
# The bootstrap configuration has separate local state and is not destroyed here.
terraform {
  backend "azurerm" {
    use_azuread_auth = true
  }
}

That's the entire file — and that's intentional. Most of the information a backend needs (which storage account, which container, which file name) is deliberately not written here.

Why not just use a local state file? the problem this solves

The default: state on your own laptoplocal backend

If a project doesn't configure a backend at all, Terraform quietly writes its state to a local terraform.tfstate file. That works fine for one person experimenting alone, but it breaks down the moment a second person, or an automated process like GitHub Actions, also needs to run Terraform — there's no single, current copy of the state everyone shares.

The fix: a shared remote backendazurerm backend

The azurerm backend type stores state as a blob inside an Azure Storage account instead. Whoever runs Terraform — a teammate locally, or the GitHub Actions workflow — reads and writes the exact same state file. Azure Storage also locks the state file while a run is in progress, so two runs can't corrupt it by writing at the same time.

use_azuread_auth = truethe one setting here

This tells Terraform to authenticate to the storage account using your (or the workflow's) Azure identity, rather than a separate storage access key that would need to be generated, stored as a secret, and rotated on its own. One less secret to manage.

Why the file looks so empty partial configuration

A full azurerm backend configuration also needs a storage account name, a container name, and a file name (called the state key). None of those appear in backend.tf — they're supplied separately, every time Terraform is initialized. This pattern is called partial configuration.

Locally: backend.hclterraform/backend.hcl.example
terraform/backend.hcl.examplestorage_account_name = "COPY-TF_STATE_STORAGE_ACCOUNT-FROM-BOOTSTRAP"
container_name       = "tfstate"
key                  = "metals.tfstate"

You copy this example file to backend.hcl, fill in the real storage account name, and run:

terraform -chdir=terraform init -backend-config backend.hcl

backend.hcl is listed in .gitignore and never committed — the storage account name isn't secret, but keeping the real file out of Git avoids every clone needing its own edit merged back in.

In GitHub Actions: command-line flagsno file needed
terraform -chdir=terraform init -input=false -lockfile=readonly \
  -backend-config="storage_account_name=$TF_STATE_STORAGE_ACCOUNT" \
  -backend-config="container_name=tfstate" \
  -backend-config="key=metals.tfstate"

The workflow supplies the same three values as individual -backend-config flags instead of a file, pulling the storage account name from a GitHub Actions variable. Same backend, same partial-configuration pattern, just filled in a different way.

Where the storage account itself comes fromchicken-and-egg

The storage account referenced here has to exist before this backend can use it — but this project's main Terraform configuration is what creates most Azure resources. That's exactly what bootstrap/main.tf is for: a separate, one-time setup that creates the state storage account first, with its own independent state.

Key terms for beginners

State
Terraform's record of exactly what it has created and how those pieces relate to each other. Terraform compares this record to your .tf files, and to real Azure, every time it runs.
Backend
The place Terraform stores its state. The default is a local file; this project uses the azurerm backend to store it remotely instead.
Partial configuration
Writing only some backend settings in backend.tf, and supplying the rest later at terraform init time — useful when a value (like a storage account name) shouldn't be hardcoded into a committed file.
State locking
A safety mechanism that prevents two Terraform runs from writing to the same state at the same time, avoiding a corrupted or conflicting record.
Codey giving a thumbs up

State has a safe home — now let's fill in the inputs Terraform needs from you.