Terragrunt allows you to use Terraform interpolation syntax
(${...}
) to call specific Terragrunt built-in functions. Note that Terragrunt built-in functions only work within a
terragrunt = { ... }
block. Terraform does NOT process interpolations in .tfvars
files.
find_in_parent_folders
find_in_parent_folders()
searches up the directory tree from the current .tfvars
file and returns the relative path
to to the first terraform.tfvars
in a parent folder or exit with an error if no such file is found. This is
primarily useful in an include
block to automatically find the path to a parent .tfvars
file:
terragrunt = {
include {
path = "${find_in_parent_folders()}"
}
}
The function takes an optional name
parameter that allows you to specify a different filename to search for:
terragrunt = {
include {
path = "${find_in_parent_folders("some-other-file-name.tfvars")}"
}
}
You can also pass an optional second fallback
parameter which causes the function to return the fallback value
(instead of exiting with an error) if the file in the name
parameter cannot be found:
terragrunt = {
include {
path = "${find_in_parent_folders("some-other-file-name.tfvars", "fallback.tfvars")}"
}
}
path_relative_to_include
path_relative_to_include()
returns the relative path between the current .tfvars
file and the path
specified in
its include
block. For example, consider the following folder structure:
├── terraform.tfvars
└── prod
└── mysql
└── terraform.tfvars
└── stage
└── mysql
└── terraform.tfvars
Imagine prod/mysql/terraform.tfvars
and stage/mysql/terraform.tfvars
include all settings from the root
terraform.tfvars
file:
terragrunt = {
include {
path = "${find_in_parent_folders()}"
}
}
The root terraform.tfvars
can use the path_relative_to_include()
in its remote_state
configuration to ensure
each child stores its remote state at a different key
:
terragrunt = {
remote_state {
backend = "s3"
config {
bucket = "my-terraform-bucket"
region = "us-east-1"
key = "${path_relative_to_include()}/terraform.tfstate"
}
}
}
The resulting key
will be prod/mysql/terraform.tfstate
for the prod mysql
module and
stage/mysql/terraform.tfstate
for the stage mysql
module.
path_relative_from_include
path_relative_from_include()
returns the relative path between the path
specified in its include
block and the current
.tfvars
file (it is the counterpart of path_relative_to_include()
). For example, consider the following folder structure:
├── sources
| ├── mysql
| | └── *.tf
| └── secrets
| └── mysql
| └── *.tf
└── terragrunt
└── common.tfvars
├── mysql
| └── terraform.tfvars
├── secrets
| └── mysql
| └── terraform.tfvars
└── terraform.tfvars
Imagine terragrunt/mysql/terraform.tfvars
and terragrunt/secrets/mysql/terraform.tfvars
include all settings from the root
terraform.tfvars
file:
terragrunt = {
include {
path = "${find_in_parent_folders()}"
}
}
The root terraform.tfvars
can use the path_relative_from_include()
in combination with path_relative_to_include()
in its source
configuration to retrieve the relative terraform source code from the terragrunt configuration file:
terragrunt = {
terraform {
source = "${path_relative_from_include()}/../sources//${path_relative_to_include()}"
}
...
}
The resulting source
will be ../../sources//mysql
for mysql
module and ../../../sources//secrets/mysql
for secrets/mysql
module.
Another use case would be to add extra argument to include the common.tfvars file for all subdirectories:
terragrunt = {
terraform = {
...
extra_arguments "common_var" {
commands = [
"apply",
"plan",
"import",
"push",
"refresh"
]
arguments = [
"-var-file=${get_tfvars_dir()}/${path_relative_from_include()}/common.tfvars",
]
}
}
}
This allows proper retrieval of the common.tfvars
from whatever the level of subdirectories we have.
get_env
get_env(NAME, DEFAULT)
returns the value of the environment variable named NAME
or DEFAULT
if that environment
variable is not set. Example:
terragrunt = {
remote_state {
backend = "s3"
config {
bucket = "${get_env("BUCKET", "my-terraform-bucket")}"
}
}
}
Note that Terraform will read environment
variables that start with the
prefix TF_VAR_
, so one way to share the a variable named foo
between Terraform and Terragrunt is to set its value
as the environment variable TF_VAR_foo
and to read that value in using this get_env()
built-in function.
get_tfvars_dir
get_tfvars_dir()
returns the directory where the Terragrunt configuration file (by default, terraform.tfvars
) lives.
This is useful when you need to use relative paths with remote Terraform
configurations and you want those paths relative to your Terragrunt configuration
file and not relative to the temporary directory where Terragrunt downloads the code.
For example, imagine you have the following file structure:
/terraform-code
├── common.tfvars
├── frontend-app
│ └── terraform.tfvars
Inside of /terraform-code/frontend-app/terraform.tfvars
you might try to write code that looks like this:
terragrunt = {
terraform {
source = "git::git@github.com:foo/modules.git//frontend-app?ref=v0.0.3"
extra_arguments "custom_vars" {
commands = [
"apply",
"plan",
"import",
"push",
"refresh"
]
arguments = [
"-var-file=../common.tfvars", # Note: This relative path will NOT work correctly!
"-var-file=terraform.tfvars"
]
}
}
}
Note how the source
parameter is set, so Terragrunt will download the frontend-app
code from the modules
repo
into a temporary folder and run terraform
in that temporary folder. Note also that there is an extra_arguments
block that is trying to allow the frontend-app
to read some shared variables from a common.tfvars
file.
Unfortunately, the relative path (../common.tfvars
) won’t work, as it will be relative to the temporary folder!
Moreover, you can’t use an absolute path, or the code won’t work on any of your teammates’ computers.
To make the relative path work, you need to use get_tfvars_dir()
to combine the path with the folder where
the .tfvars
file lives:
terragrunt = {
terraform {
source = "git::git@github.com:foo/modules.git//frontend-app?ref=v0.0.3"
extra_arguments "custom_vars" {
commands = [
"apply",
"plan",
"import",
"push",
"refresh"
]
# With the get_tfvars_dir() function, you can use relative paths!
arguments = [
"-var-file=${get_tfvars_dir()}/../common.tfvars",
"-var-file=terraform.tfvars"
]
}
}
}
For the example above, this path will resolve to /terraform-code/frontend-app/../common.tfvars
, which is exactly
what you want.
get_parent_tfvars_dir
get_parent_tfvars_dir()
returns the absolute directory where the Terragrunt parent configuration file (by default, terraform.tfvars
) lives.
This is useful when you need to use relative paths with remote Terraform configurations and you want
those paths relative to your parent Terragrunt configuration file and not relative to the temporary directory where Terragrunt downloads
the code.
This function is very similar to get_tfvars_dir() except it returns the root instead of the leaf of your terragrunt configuration folder.
/terraform-code
├── terraform.tfvars
├── common.tfvars
├── app1
│ └── terraform.tfvars
├── tests
│ ├── app2
│ | └── terraform.tfvars
│ └── app3
│ └── terraform.tfvars
terragrunt = {
terraform {
extra_arguments "common_vars" {
commands = [
"apply",
"plan",
"import",
"push",
"refresh"
]
arguments = [
"-var-file=${get_parent_tfvars_dir()}/common.tfvars"
]
}
}
}
The common.tfvars located in the terraform root folder will be included by all applications, whatever their relative location to the root.
get_terraform_commands_that_need_vars
get_terraform_commands_that_need_vars()
Returns the list of terraform commands that accept -var and -var-file parameters. This function is used when defining extra_arguments.
terragrunt = {
terraform = {
...
extra_arguments "common_var" {
commands = ["${get_terraform_commands_that_need_vars()}"]
arguments = ["-var-file=${get_aws_account_id()}.tfvars"]
}
}
}
get_terraform_commands_that_need_input
get_terraform_commands_that_need_input()
Returns the list of terraform commands that accept -input=(true or false) parameter. This function is used when defining extra_arguments.
terragrunt = {
terraform {
# Force Terraform to not ask for input value if some variables are undefined.
extra_arguments "disable_input" {
commands = ["${get_terraform_commands_that_need_input()}"]
arguments = ["-input=false"]
}
}
}
get_terraform_commands_that_need_locking
get_terraform_commands_that_need_locking()
Returns the list of terraform commands that accept -lock-timeout parameter. This function is used when defining extra_arguments.
terragrunt = {
terraform {
# Force Terraform to keep trying to acquire a lock for up to 20 minutes if someone else already has the lock
extra_arguments "retry_lock" {
commands = ["${get_terraform_commands_that_need_locking()}"]
arguments = ["-lock-timeout=20m"]
}
}
}
Note: Functions that return a list of values must be used in a single declaration like:
commands = ["${get_terraform_commands_that_need_vars()}"]
# which result in:
commands = ["apply", "console", "destroy", "import", "plan", "push", "refresh"]
# We do not recommend using them in string composition like:
commands = "Some text ${get_terraform_commands_that_need_locking()}"
# which result in something useless like:
commands = "Some text [apply destroy import init plan refresh taint untaint]"
get_aws_account_id
get_aws_account_id()
returns the AWS account id associated with the current set of credentials. Example:
terragrunt = {
remote_state {
backend = "s3"
config {
bucket = "mycompany-${get_aws_account_id()}"
}
}
}
This allows uniqueness of the storage bucket per AWS account (since bucket name must be globally unique).
It is also possible to configure variables specifically based on the account used:
terragrunt = {
terraform = {
...
extra_arguments "common_var" {
commands = ["${get_terraform_commands_that_need_vars()}"]
arguments = ["-var-file=${get_aws_account_id()}.tfvars"]
}
}
}