Article · part of a guide
Dynamic Backend Blocks with OpenTofu
Using variables in backend configurations makes it much easier to scale your OpenTofu usage compared to Terraform.

Key takeaways
- OpenTofu lets you use input variables and local values directly inside the backend block, unlike Terraform where the backend configuration is static.
- Dynamic backends enable multi-environment deployments, region-specific state, dynamic credentials, and simpler CI/CD pipelines without editing core configuration files.
- Variables used in the backend block must be resolvable at tofu init time, supplied via -var flags, -backend-config flags, or TF_VAR environment variables rather than auto-loaded tfvars files.
- You cannot reference values derived from state inside the backend block, because the backend must be initialized before state is available.
One of the things OpenTofu gives you over Terraform is the ability to use configuration variables directly inside the backend block. People call this a "dynamic backend block," and it gives you a lot of room to manage state, especially in complex or multi-environment setups.
In Terraform the backend configuration has always been static. You had to work around it by generating backend config files on the fly or leaning hard on command-line flags during terraform init, like -backend-config as mentioned in this blog. OpenTofu drops that restriction and lets you define backend parameters with input variables and local values.
Why Dynamic Backends Matter
Once you can configure your backend dynamically, a few useful patterns open up:
- Multi-environment deployments: Easily switch between different state backends (e.g., S3 buckets, Azure Storage containers) for development, staging, and production without modifying your core OpenTofu configuration files.
- Region-specific state: Store state in regions corresponding to your infrastructure deployments, improving latency and data residency compliance.
- Dynamic credentials: Pass sensitive credentials for backend access via variables, avoiding hardcoding them in your configuration.
- Simplified CI/CD pipelines: Streamline automation by allowing CI/CD systems to inject backend configurations based on pipeline variables or environment-specific logic.
How to Use Variables in OpenTofu Backends
1. Using Input Variables
You can define variables and then reference them directly within your backend block.
variable "env" {
description = "The deployment environment (e.g., dev, prod)"
type = string
default = "dev"
}
variable "aws_region" {
description = "The AWS region for state storage"
type = string
default = "us-east-1"
}
terraform {
backend "s3" {
bucket = "my-opentofu-state"
key = "path/to/my/state/${var.env}.tfstate"
region = var.aws_region
encrypt = true
}
}In this example, the state file key is dynamically constructed based on the env variable, and aws_region is also pulled from a variable. You can set these via terraform.tfvars files, environment variables (TF_VAR_env), or command-line arguments (-var="env=prod").
2. Using Local Values
Local values let you put a name on an expression you can reuse throughout your configuration, including the backend block. They're handy for derived values.
variable "workspace_name" {
description = "The name of the OpenTofu workspace"
type = string
}
locals {
s3_bucket_prefix = "my-company-opentofu-states"
s3_key_path = "${local.s3_bucket_prefix}/${var.workspace_name}/terraform.tfstate"
s3_region_map = {
"us" = "us-west-2"
"eu" = "eu-central-1"
}
backend_region = local.s3_region_map[split("-", var.workspace_name)[0]]
}
terraform {
backend "s3" {
bucket = local.s3_bucket_prefix
key = local.s3_key_path
region = local.backend_region
encrypt = true
}
}Here, s3_bucket_prefix and s3_key_path are defined as locals for better readability and reusability. The example also derives backend_region from a portion of workspace_name using a map lookup.
3. Dynamic AWS Assume Role Credentials
This works for sensitive bits too, like the assume_role block in an S3 backend.
variable "account_id" {
description = "The AWS account ID for assuming a role"
type = string
}
terraform {
backend "s3" {
bucket = "my-secure-opentofu-state"
key = "prod/terraform.tfstate"
region = "us-east-1"
assume_role {
role_arn = "arn:aws:iam::${var.account_id}:role/opentofu-backend-access"
}
}
}Now the same backend config can target different AWS accounts or environments without any code changes.
Important Considerations
tofu initrequirement: Backend configuration is evaluated duringtofu init. Any variables used in the backend block must be resolvable atinittime. You can provide these values via:-varcommand-line flags-backend-configcommand-line flags (for partial configuration)- Environment variables (
TF_VAR_NAME) - Note:
terraform.tfvarsfiles are not automatically loaded for backend configuration duringinitif the backend block itself depends on variables from them.
- No state references: You cannot reference values from the state or locals derived from the state within the
backendblock, since the backend must be initialized before the state is available. - Security: Be mindful of how you pass sensitive information to backend configuration. Environment variables are generally preferred over hardcoding, especially in CI/CD environments.
Configuration variables in backend blocks let you keep one set of OpenTofu files across environments instead of maintaining separate backend configs or passing long lists of -backend-config flags. Define the variables your backend needs, make sure they resolve at init time, and the same code targets dev, staging, and production state.
If you'd rather not manage the state buckets and locking behind those backends at all, a managed platform provides them for you. Scalr runs OpenTofu with remote state and locking built in on usage-based pricing that's free up to 50 runs a month.
About the author

director 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.
Part of this guide
19 sheets
Terraform State & Backends: The Complete Guide
- How to Update State in a Remote Backend
- HashiCorp GPG Key Expired: Fixing Terraform Download Errors
- Terraform State Files Best Practices
- Using the AWS S3 Backend Block in Terraform
- Using the AzureRM Backend Block in Terraform
- Using the GCS Backend Block in Terraform
- How to Share Terraform State
- Scalr Terraform State Management: Features and Functionality
- A beginner's guide to the terraform init command
- Understanding OpenTofu Remote Backends
- Updating Terraform State, with Great Power comes Great Responsibility
- Why Use A Remote Operations Backend Over A Standard Backend
- How To Use Terraform Remote Backends
- Get Started With Scalr & Terraform CLI on AWS
- Get Started With Scalr & Terraform CLI on Azure
- Get Started With Scalr & Terraform CLI on GCP
- How To: Migrate Terraform State Into Scalr