TrademarkTrademark
Features
Documentation

Using the AzureRM Backend Block in Terraform

Using the AzureRM backend makes it much easier to scale your Terraform usage.
Ryan FeeMarch 4, 2026Updated March 31, 2026
Using the AzureRM Backend Block in Terraform
Key takeaways
  • The Terraform azurerm backend stores state files in Azure Blob Storage, enabling team collaboration, state locking, and secure durable storage.
  • A basic azurerm backend block specifies resource_group_name, storage_account_name, container_name, and key, requiring a pre-existing storage account and container.
  • Authenticate without hardcoding credentials by using environment variables, the Azure CLI session from az login, or a Managed Identity with the Storage Blob Data Contributor role.
  • Terraform forbids variables inside the backend block, but OpenTofu 1.8 introduced support for variables and local values, enabling dynamic per-environment backend configuration.

If you're using Terraform to manage Azure infrastructure, you'll want a remote backend instead of keeping state on your laptop. The azurerm backend block stores your Terraform state files in Azure Blob Storage. That gives your team a shared place to read and write state, with locking so two people don't apply at the same time.

The Terraform state file is a JSON file that records your deployed resources. It maps your configuration to the real resources in your Azure subscription. Storing that file remotely with the azurerm backend buys you a few things:

  • Collaboration: It allows multiple team members to work on the same infrastructure without overwriting each other's changes.
  • State Locking: It prevents concurrent terraform apply operations, which can lead to state file corruption and resource conflicts. Azure Blob Storage's native leasing feature handles this locking automatically.
  • Security & Durability: State files can contain sensitive data. Storing them in a secure, encrypted, and highly available Azure storage account is a best practice.

Basic Usage and Configuration

To use the azurerm backend, you need an Azure Storage Account and a container inside it that already exist. It's good practice to create a dedicated storage account just for your Terraform state files.

Here's a basic azurerm backend block configuration:

terraform {
  backend "azurerm" {
    resource_group_name  = "terraform-state-rg"
    storage_account_name = "myterraformstateaccount"
    container_name       = "tfstate"
    key                  = "my-app.tfstate"
  }
}
  • resource_group_name: The name of the resource group where your storage account is located.
  • storage_account_name: The globally unique name of your Azure Storage Account.
  • container_name: The name of the blob container where the state file will be stored.
  • key: The name of the blob (the state file itself) within the container. You should use a unique key for each separate Terraform configuration.

Once you've added this block to your main Terraform configuration file, run terraform init. That command sets up the backend and asks if you want to migrate any existing local state to the remote location.


Use Cases

The azurerm backend is essential for any serious Terraform project.

  • Team Projects: When multiple developers are working on a single infrastructure, the azurerm backend ensures everyone is using the same, up-to-date state file. This prevents developers from accidentally managing resources they shouldn't.
  • CI/CD Pipelines: In a continuous integration and continuous deployment (CI/CD) workflow, the pipeline needs a consistent place to read and write the state file. The azurerm backend provides a reliable and secure endpoint for tools like Azure DevOps, GitHub Actions, or Jenkins to execute Terraform.
  • Production Environments: For production infrastructure, the azurerm backend is non-negotiable. Its built-in state locking and data durability features are critical for preventing downtime and ensuring the integrity of your production environment.

Authentication Methods

Authentication matters a lot with the azurerm backend. Never hardcode credentials like access keys directly in your configuration. Use one of the supported authentication methods instead:

Environment Variables: The most common approach. Terraform can automatically use credentials set in environment variables like ARM_CLIENT_ID, ARM_CLIENT_SECRET, and ARM_TENANT_ID.

export ARM_SUBSCRIPTION_ID="<your-subscription-id>"
export ARM_CLIENT_ID="<your-service-principal-client-id>"
export ARM_CLIENT_SECRET="<your-service-principal-client-secret>"
export ARM_TENANT_ID="<your-tenant-id>"

Azure CLI: If you're logged in via az login, Terraform can use that session to authenticate. This is a great option for local development.

Run Terraform commands without any extra authentication configuration:

terraform init

Set your subscription (if you have multiple):

az account set --subscription="<your-subscription-id>"

Log in to Azure:

az login

Terraform will find the cached credentials and use them.

Managed Identity (MSI): For resources like Azure Functions, Virtual Machines, or Azure DevOps agents, you can use a Managed Identity to authenticate. This is a highly secure, password-less method.

A Virtual Machine, for example, can be assigned an identity that has permissions to access other Azure resources.

  1. Enable a system-assigned or user-assigned identity on your Azure resource.
  2. Grant the identity the Storage Blob Data Contributor role on the storage account where your state file is stored.
  3. Your Terraform process, when run on that resource, will automatically authenticate using the managed identity. No credentials are needed in your configuration or environment variables.

Best Practices

Separate State: Use a separate storage account and container for each environment (e.g., dev, stage, prod). This isolates state files and prevents accidental cross-environment changes.

Permission Scoping: Grant the service principal or managed identity the Storage Blob Data Contributor role scoped to the specific storage account or container. This follows the principle of least privilege.

Versioning: Enable versioning on your Azure Blob Storage container. This gives you a history of your state files and allows you to revert to a previous version if something goes wrong.


Advanced Concepts

Partial Backend Configuration

Terraform won't let you use variables directly inside the backend block (OpenTofu does, see more below). But you can leave out sensitive or environment-specific values and supply them at runtime with a backend configuration file or command-line flags on terraform init.

Example using a file:

Run terraform init**:**

terraform init -backend-config="backend.conf"

backend.conf :

storage_account_name = "myterraformstateaccount"
resource_group_name = "terraform-state-rg"

main.tf (partial config):

terraform {
  backend "azurerm" {
    container_name = "tfstate"
    key            = "my-app.tfstate"
  }
}

This method prevents sensitive information from being committed to source control.

Managing Multiple Environments with Workspaces

For a single configuration that deploys to multiple environments, Terraform workspaces can be used to manage different state files within the same container.

Example:

# Create and switch to a development workspace
terraform workspace new dev

# Create and switch to a production workspace
terraform workspace new prod

When you switch between workspaces, Terraform automatically changes the key to include the workspace name (e.g., env:/dev/my-app.tfstate), ensuring each environment has its own isolated state file.

A Note on OpenTofu and Dynamic Backends

The classic Terraform CLI sticks to its strict rule against dynamic backend blocks. OpenTofu, a fork of Terraform, does it differently.

Starting with version 1.8, OpenTofu added the ability to use variables and local values inside the backend block. That's a big deal, since it answers one of the longest-standing requests in the Terraform community.

With OpenTofu, you can write a more flexible and DRY (Don't Repeat Yourself) backend configuration, which really helps for multi-environment setups.

Here's how a dynamic azurerm backend block could look in OpenTofu:

variable "env" {
  type    = string
  default = "dev"
}

terraform {
  backend "azurerm" {
    resource_group_name  = "terraform-state-${var.env}-rg"
    storage_account_name = "myterraformstate${var.env}"
    container_name       = "tfstate"
    key                  = "my-app-${var.env}.tfstate"
  }
}

This simple configuration allows you to switch between environments by simply changing the env variable. You can pass the variable at the command line or file:

tofu init -var="env=prod"

Now you don't need separate backend configuration files or fiddly scripts to handle different environments, so your codebase stays cleaner and you make fewer manual mistakes. If you're managing a lot of similar environments, or you just prefer a shorter, variable-driven config, OpenTofu's support for dynamic backend blocks is a big win. See a full blog on this here.

This blog has been verified for Terraform and OpenTofu

About the author
Ryan Feedirector of platform engineering at Scalr
Ryan Fee is the director of platform engineering at Scalr, with over 15 years of experience improving infrastructure experiences at companies large and small.