Terraform Shared Remote State on Azure

Safely manage dev and prod environments in Terraform on Azure using isolated remote state. Avoid accidental resource deletion and switch environments confidently.

About this post

  • Created 2025-12-26

  • TerraformAzureIaC

Intro

When configuring cloud environments differently for dev and prod, you need separate state files for each. This post shows how to safely isolate Terraform state per environment using shared Azure Storage backends.

The Core Problem: Shared Terraform State

Terraform uses a state file to track what infrastructure it manages. By default, this state is stored locally in terraform.tfstate.

If you apply Terraform with different variable files (e.g. dev.tfvars and prod.tfvars) but use the same state, Terraform will try to reconcile both environments as one. The result is usually resource deletion in the “other” environment.

The solution is state isolation.

The Correct Pattern: One Codebase, Multiple States

  • One Terraform codebase
  • Separate state files for dev and prod
  • Azure Storage as a remote backend
  • No manual editing of .tf files when switching environments
  • Terraform supports this natively using remote backends + backend reconfiguration

Declaring the Backend (Minimal Configuration)

The backend must be declared in Terraform code in providers.tf, but it should be kept minimal:

terraform {
  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "4.57.0"
    }
  }

  # Use an Azure backend
  backend "azurerm" {}
}

This tells Terraform to use an Azure backend, but the actual configuration will be provided at init time.

Azure Provider Configuration

The provider block also goes into providers.tf, but is separate from the backend and is responsible for creating resources in Azure, not storing state.

If you have one subscription for dev and one for prod, you can declare an environment variable using export ARM_SUBSCRIPTION_ID=YOUR_SUB_ID, or inline the variable when calling terraform apply.

provider "azurerm" {
  features        = {}
  subscription_id = var.subscription_id
}

Environment-Specific Backend Configuration

Create one backend config file per environment. These are just example namings.

backend-dev.tfvars

resource_group_name  = "tfstate-rg"
storage_account_name = "tfstateacct12345"
container_name       = "tfstate"
key                  = "dev.terraform.tfstate"

backend-prod.tfvars

resource_group_name = "tfstate-rg"
storage_account_name = "tfstateacct12345"
container_name = "tfstate"
key = "prod.terraform.tfstate"

The key determines the actual state file (blob) inside the container. Different keys = different states.

Initializing and Switching Environments

Initialize Dev

terraform init -reconfigure -backend-config=backend-dev.tfvars
terraform apply -var-file=dev.tfvars

Swith to Prod

terraform init -reconfigure -backend-config=backend-prod.tfvars
terraform apply -var-file=prod.tfvars

When applying the Terraform configuration, we provide the environment-specific .tfvars file. This lets us define the infrastructure once and dynamically swap values per environment.

Why -reconfigure?

If you only run terraform init -backend-config=backend-prod.tfvars without the flag, Terraform detects that the backend configuration has changed and asks whether to migrate state.

Error: Backend configuration changed
 A change in the backend configuration has been detected, which may require migrating existing state.
 If you wish to attempt automatic migration of the state, use "terraform init -migrate-state".
 If you wish to store the current configuration with no changes to the state, use "terraform init -reconfigure".

When switching environments, you do not want to migrate state, but instead you only want to switch which state file Terraform uses.

Summary

  • Declare a minimal Azure backend in Terraform
  • Use Azure Storage for remote state
  • Isolate environments using different backend keys
  • Switch environments using terraform init -reconfigure

Could be useful