The remote_state block configures the backend that stores a unit’s state, so you can set it once in a file every unit includes. See State backend.
Terragrunt passes the config map to the OpenTofu/Terraform backend block:
terragrunt.hcl
remote_state {
backend ="s3"
config ={
bucket="mybucket"
key="path/to/my/key"
region="us-east-1"
}
}
Equivalent OpenTofu/Terraform
terraform {
backend "s3" {
bucket ="mybucket"
key ="path/to/my/key"
region ="us-east-1"
}
}
Without generate, the module needs an empty backend block of the same type, e.g. terraform { backend "s3" {} }, for Terragrunt to fill in.
Setting remote_state as an attribute
remote_state also works as an attribute, so a unit can set it from another file:
terragrunt.hcl
locals {
common = read_terragrunt_config(find_in_parent_folders("common.hcl"))
}
remote_state =local.common.remote_state
Backend bootstrapping
With --backend-bootstrap, or with terragrunt backend bootstrap, Terragrunt creates the backend’s storage before init if it’s missing, e.g. an S3 bucket, and checks its configuration if it exists. It can do that for the s3, gcs, and azurerm backends.
Otherwise, Terragrunt leaves the storage alone, and init fails if the storage doesn’t exist. disable_init = true makes Terragrunt leave it alone even with --backend-bootstrap.
Encrypting state
The encryption map needs a key_provider key, set to any key provider OpenTofu supports, e.g. pbkdf2, aws_kms, gcp_kms, or openbao. Its other keys configure that provider. Terragrunt turns the map into an encryption block in the OpenTofu terraform block:
terragrunt.hcl
remote_state {
backend ="s3"
config ={
bucket="mybucket"
key="path/to/my/key"
region="us-east-1"
}
encryption ={
key_provider="pbkdf2"
passphrase=get_env("PBKDF2_PASSPHRASE")
}
}
Generated OpenTofu
terraform {
backend "s3" {
bucket ="mybucket"
key ="path/to/my/key"
region ="us-east-1"
}
encryption {
key_provider "pbkdf2""default" {
passphrase ="SUPERSECRETPASSPHRASE"
}
method "aes_gcm""default" {
keys =key_provider.pbkdf2.default
}
state {
method =method.aes_gcm.default
}
plan {
method =method.aes_gcm.default
}
}
}
Two keys in the encryption map go to the generated state and plan blocks instead of the key provider:
fallback: Set to { method = "unencrypted" } to let OpenTofu read state and plan files written before encryption was enabled. Any other value is an error.
enforced: Set to true to make OpenTofu error instead of writing unencrypted state or plan files.
Once encryption is configured, OpenTofu refuses to read plaintext state. A unit with existing state therefore needs the fallback for one run, as described under pre-existing project in the OpenTofu docs:
terragrunt.hcl
remote_state {
backend ="s3"
config ={
bucket="mybucket"
key="path/to/my/key"
region="us-east-1"
}
encryption ={
key_provider="pbkdf2"
passphrase=get_env("PBKDF2_PASSPHRASE")
fallback= { method="unencrypted" }
}
}
Terragrunt adds an unencrypted method and points both blocks at it:
backend.tf
encryption {
# key_provider and method "aes_gcm" as above
method "unencrypted""fallback" {
}
state {
method =method.aes_gcm.default
fallback {
method =method.unencrypted.fallback
}
}
plan {
method =method.aes_gcm.default
fallback {
method =method.unencrypted.fallback
}
}
}
Run terragrunt apply so OpenTofu writes the state back encrypted. Then replace fallback with enforced = true.
Examples
Stores state in the S3 bucket my-tofu-state, with a key per unit, e.g. child/tofu.tfstate for a unit in child. Terragrunt can create the bucket and the DynamoDB lock table.
root.hcl
remote_state {
backend ="s3"
config ={
bucket="my-tofu-state"
key="${path_relative_to_include()}/tofu.tfstate"
region="us-east-1"
encrypt=true
dynamodb_table="my-lock-table"
}
}
Stores state in the GCS bucket my-tofu-state, and labels the bucket if Terragrunt creates it.
root.hcl
remote_state {
backend ="gcs"
config ={
project="my-tofu"
location="eu"
bucket="my-tofu-state"
prefix=path_relative_to_include()
gcs_bucket_labels= {
owner="terragrunt_test"
name="tofu_state_storage"
}
}
}
Stores state in the tfstate container of the Azure storage account mytofustate. Reading and writing state with use_azuread_auth needs the Storage Blob Data Contributor role on the account. Set assign_blob_data_role = true to have bootstrapping grant it.
root.hcl
remote_state {
backend ="azurerm"
config ={
resource_group_name="my-tofu-state"
storage_account_name="mytofustate"
container_name="tfstate"
key="${path_relative_to_include()}/tofu.tfstate"
location="eastus"
use_azuread_auth=true
}
}
Locks state with S3 native locking instead of DynamoDB. It needs OpenTofu 1.10 or later.
root.hcl
remote_state {
backend ="s3"
config ={
bucket="my-tofu-state"
key="${path_relative_to_include()}/tofu.tfstate"
region="us-east-1"
encrypt=true
use_lockfile=true
}
}
Takes both locks while you migrate from DynamoDB to S3 native locking. Once the migration is done, remove dynamodb_table. Terragrunt doesn’t delete the table.
root.hcl
remote_state {
backend ="s3"
config ={
bucket="my-tofu-state"
key="${path_relative_to_include()}/tofu.tfstate"
region="us-east-1"
encrypt=true
dynamodb_table="my-lock-table"
use_lockfile=true
}
}
Attributes
backendstring
The backend to store state in, e.g. s3, gcs, or azurerm.
terragrunt.hcl
remote_state {
backend ="s3"
config ={
bucket="my-tofu-state"
key="vpc/tofu.tfstate"
region="us-east-1"
}
}
configmap(any)
The backend’s configuration. Terragrunt passes it to the OpenTofu/Terraform backend block, except for the keys Terragrunt uses to create the backend’s storage. See Backend config keys.
Writes the backend configuration to a .tf file, so the module needs no backend block of its own. path is the file to write, relative to the directory Terragrunt runs OpenTofu/Terraform in. if_exists sets what happens when the file exists: overwrite, overwrite_terragrunt to overwrite only a file Terragrunt generated and fail otherwise, skip, or error.
terragrunt.hcl
remote_state {
backend ="s3"
config ={
bucket="my-tofu-state"
key="vpc/tofu.tfstate"
region="us-east-1"
}
generate ={
path="backend.tf"
if_exists="overwrite_terragrunt"
}
}
disable_initoptional(bool, false)
Stops Terragrunt from creating or updating the backend’s storage, e.g. an S3 bucket. OpenTofu/Terraform still initializes the backend, and generate still writes the backend configuration. Terragrunt can create storage for the s3, gcs, and azurerm backends. See Backend bootstrapping.
Turns off Terragrunt’s optimized fetching of dependency outputs for units with this remote_state block.
terragrunt.hcl
remote_state {
backend ="s3"
config ={
bucket="my-tofu-state"
key="vpc/tofu.tfstate"
region="us-east-1"
}
disable_dependency_optimization =true
}
encryptionoptional(map(any))
State and plan encryption for OpenTofu. Its key_provider key names an OpenTofu key provider, and the other keys configure it. See Encrypting state.
terragrunt.hcl
remote_state {
backend ="s3"
config ={
bucket="my-tofu-state"
key="vpc/tofu.tfstate"
region="us-east-1"
}
encryption ={
key_provider="pbkdf2"
passphrase=get_env("PBKDF2_PASSPHRASE")
}
}
Backend config keys
For the s3, gcs, and azurerm backends, Terragrunt reads these config keys to provision the backend’s storage. It passes every key on to the OpenTofu/Terraform backend except the ones used only for provisioning.
Used by Terragrunt for backend provisioning
S3backend = "s3"
bucketstring
The S3 bucket that stores state. Terragrunt creates it when it bootstraps the backend.
keystring
The path of the state file in the bucket.
regionstring
The bucket’s AWS region.
profileoptional(string)
The AWS profile name, as set in the shared credentials file.
shared_credentials_fileoptional(string)
The path to the shared credentials file. With a profile and no file, Terragrunt uses ~/.aws/credentials.
role_arnoptional(string)
The role to assume. assume_role.role_arn takes precedence.
external_idoptional(string)
The external ID to use when assuming the role. assume_role.external_id takes precedence.
session_nameoptional(string)
The session name to use when assuming the role. assume_role.session_name takes precedence.
assume_roleoptional(object)
Settings for assuming a role, for Terraform 1.6 or later.
role_arnstring
The role to assume.
durationoptional(string)
How long the credentials are valid.
external_idoptional(string)
The external ID to use when assuming the role.
policyoptional(string)
A JSON policy that further restricts the role.
policy_arnsoptional(list(string))
Policy ARNs that further restrict the role.
session_nameoptional(string)
The session name to use when assuming the role.
source_identityoptional(string)
The source identity to use when assuming the role.
tagsoptional(map(string))
Session tags for the assumed role.
transitive_tag_keysoptional(list(string))
Tag keys to pass on to later sessions.
assume_role_with_web_identityoptional(object)
Settings for assuming a role with a web identity token. Terragrunt passes them on to OpenTofu/Terraform and doesn’t use them itself.
role_arnstring
The role to assume.
durationoptional(string)
How long the credentials are valid.
policyoptional(string)
A JSON policy that further restricts the role.
policy_arnsoptional(list(string))
Policy ARNs that further restrict the role.
session_nameoptional(string)
The session name to use when assuming the role.
web_identity_tokenoptional(string)
The web identity token. Set this or web_identity_token_file.
web_identity_token_fileoptional(string)
The path to a file holding the web identity token.
endpointoptional(string)
A custom endpoint for the S3 API. OpenTofu deprecates it in favor of endpoints.s3.
dynamodb_endpointoptional(string)
A custom endpoint for the DynamoDB API. OpenTofu deprecates it in favor of endpoints.dynamodb.
endpointsoptional(object)
Custom service endpoints, for Terraform 1.6 or later. They take precedence over endpoint and dynamodb_endpoint.
s3optional(string)
A custom endpoint for the S3 API. Set this or endpoint, because OpenTofu rejects both together.
dynamodboptional(string)
A custom endpoint for the DynamoDB API. Set this or dynamodb_endpoint, because OpenTofu rejects both together.
force_path_styleoptional(bool, false)
Addresses the bucket with path-style URLs, which most S3-compatible object stores need. OpenTofu deprecates it in favor of use_path_style.
use_path_styleoptional(bool, false)
The newer name for force_path_style. Set this or force_path_style, because OpenTofu rejects both together.
encryptoptional(bool, false)
Enables server-side encryption of the state file. When it’s off, Terragrunt logs a warning, or a debug message if skip_bucket_ssencryption is set.
dynamodb_tableoptional(string)
A DynamoDB table for state locking, with a primary key named LockID. Terragrunt creates it when it bootstraps the backend. Without it, DynamoDB locking is off.
lock_tabledeprecatedoptional(string)
The old name for dynamodb_table. Terragrunt logs a warning and uses it as dynamodb_table.
use_lockfileoptional(bool, false)
Locks state with S3 conditional writes. It needs OpenTofu 1.10 or later. It can run with dynamodb_table during a migration, when both locks must succeed.
skip_credentials_validationoptional(bool, false)
Skips Terragrunt’s check that the AWS credentials are valid.
skip_bucket_versioningoptional(bool, false)
Skips enabling versioning on the bucket Terragrunt creates.
skip_bucket_ssencryptionoptional(bool, false)
Skips configuring server-side encryption on the bucket Terragrunt creates.
Adds a bucket policy statement granting s3:* on the bucket and its objects to arn:aws:iam::<account-id>:root. Despite its name, that ARN grants access to the whole AWS account, not only its root user. Terragrunt adds the statement to existing buckets as well as ones it creates.
disable_bucket_updateoptional(bool, false)
Stops Terragrunt from updating an existing bucket to match the configuration.
bucket_sse_algorithmoptional(string, "aws:kms")
The server-side encryption algorithm for the bucket.
bucket_sse_kms_key_idoptional(string)
The KMS key for aws:kms encryption. Defaults to the AWS managed aws/s3 key.
Enables server-side encryption on the DynamoDB lock table.
dynamodb_table_tagsoptional(map(string))
Tags for the DynamoDB lock table Terragrunt creates.
disable_aws_client_checksumsoptional(bool, false)
Turns off request and response checksums, such as the CRC32 check for DynamoDB. See #1059 for when this helps.
accesslogging_bucket_nameoptional(string)
A bucket for the state bucket’s access logs, which Terragrunt creates. Without a valid bucket name, access logging is off. With access logging on, the state bucket supports only AES256 encryption. See S3 server access logging.
accesslogging_target_prefixoptional(string, "…")
The prefix for access log objects. An empty string sets an empty prefix. It needs accesslogging_bucket_name.
Has no effect, since Terragrunt sets no ACL. Use skip_accesslogging_bucket_policy to skip the grant. Terragrunt logs a warning. See the skip-accesslogging-bucket-acl strict control.
GCSbackend = "gcs"
bucketstring
The GCS bucket that stores state. Terragrunt creates it when it bootstraps the backend.
credentialsoptional(string)
The local path to a GCP service account credentials file in JSON format. Terragrunt takes only a path here.
The delegation chain for impersonating impersonate_service_account.
projectoptional(string)
The GCP project to create the bucket in.
locationoptional(string)
The GCP location to create the bucket in.
gcs_bucket_labelsoptional(map(string))
Labels for the bucket Terragrunt creates.
skip_bucket_creationoptional(bool, false)
Stops Terragrunt from creating the bucket.
skip_bucket_versioningoptional(bool, false)
Skips enabling versioning on the bucket Terragrunt creates.
enable_bucket_policy_onlyoptional(bool, false)
Gives the bucket Terragrunt creates uniform bucket-level access.
See GCS backend for the authentication order and known limitations.
Azure Storagebackend = "azurerm"
Terragrunt also reads the backend’s authentication keys, e.g. use_azuread_auth, client_id, or sas_token, and passes them on.
storage_account_namestring
The storage account that stores state.
container_namestring
The blob container that stores state.
keystring
The name of the state blob in the container.
resource_group_nameoptional(string)
The resource group of the storage account. Terragrunt needs it to create or inspect the account, but not to authenticate with a SAS token or an access key.
locationoptional(string)
The Azure region for the resource group and storage account, e.g. eastus. Required when Terragrunt creates them.
account_kindoptional(string, "StorageV2")
The storage account kind.
account_tieroptional(string, "Standard")
The storage account tier, Standard or Premium.
account_replication_typeoptional(string, "LRS")
The replication type, e.g. LRS, GRS, or ZRS.
access_tieroptional(string, "Hot")
The blob access tier, Hot, Cool, Cold, or Premium.
minimum_tls_versionoptional(string, "TLS1_2")
The minimum TLS version for requests to the storage account, TLS1_2 or TLS1_3. It applies only when Terragrunt creates the account.
tagsoptional(map(string))
Tags for the storage account Terragrunt creates.
skip_resource_group_creationoptional(bool, false)
Stops Terragrunt from creating the resource group.
Stops Terragrunt from creating the storage account, so it must exist.
skip_container_creationoptional(bool, false)
Stops Terragrunt from creating the blob container, so it must exist.
skip_versioningoptional(bool, false)
Skips enabling blob versioning on the account.
enable_soft_deleteoptional(bool, false)
Enables blob and container soft delete.
soft_delete_retention_daysoptional(number, 7)
The soft delete retention in days, from 1 to 365.
allow_blob_public_accessoptional(bool, false)
Lets containers on the account allow anonymous access.
assign_blob_data_roleoptional(bool, false)
Makes bootstrapping grant Storage Blob Data Contributor on the storage account to principal_id, or to the identity Terragrunt authenticated as when it’s unset. It needs permission to create role assignments.
principal_idoptional(string)
The Microsoft Entra object ID that receives the data-plane role when assign_blob_data_role is true.
msi_resource_idoptional(string)
The resource ID of a user-assigned managed identity to use with use_msi.
For a premium account that stores state as block blobs, set account_kind = "BlockBlobStorage", account_tier = "Premium", and access_tier = "Premium", with LRS or ZRS replication. Setting only account_tier = "Premium" keeps the StorageV2 and Hot defaults, which don’t form a valid block blob account.