Backend config:

```hcl
terraform {
  backend "azurerm" {
    resource_group_name  = "[rg]"
    storage_account_name = "[state-account]"
    container_name       = "tfstate"
    key [your value]
  }
}
```

Bootstrap (chicken-and-egg, do once by hand or in a bootstrap template):

1. Create the resource group, storage account (with versioning + soft delete on the blob service), and container. Enable blob versioning: a corrupt state write becomes recoverable.
2. `terraform init` with backend auth: same ARM_ env vars / OIDC as the provider, or `-backend-config` with a SAS. Backend auth is separate from provider auth; init failing while plan works is always this.
3. `terraform plan` / `apply`. The lease lock prevents concurrent applies.

Rules:

- **One state file per environment** (key [your value] Sharing state across envs is how prod gets staging's changes.
- **State locking is not optional.** Never `-lock=false` in automation; a crashed apply without a lock is how state corrupts.
- **Do not store secrets in state.** State files contain resource attributes in plaintext, including any secret you put in config. Secrets go in Key Vault, referenced, never in tfvars committed to git.
- **State surgery.** `terraform state mv/rm/import` for refactors. Back up the blob before surgery (versioning gives you this free).

Verify: two consecutive applies from different machines both work, the second shows no changes, and the blob has versions accumulating.