Overview
Terragrunt configuration is defined in HCL files. This uses the same HCL syntax as OpenTofu/Terraform itself.
Hereâs an example:
include "root" { path = find_in_parent_folders("root.hcl")}
dependencies { paths = ["../vpc", "../mysql", "../redis"]}
The core of Terragrunt configuration is that of the unit, which is canonically defined using terragrunt.hcl
files.
Terragrunt also supports JSON-serialized HCL defined in terragrunt.hcl.json
files. Where terragrunt.hcl
is mentioned in documentation, you can always use terragrunt.hcl.json
instead.
When determining the configuration for a unit, Terragrunt figures out the path to its configuration file according to the following rules:
-
The value of the
--config
command-line option, if specified. -
The value of the
TG_CONFIG
environment variable, if defined. -
A
terragrunt.hcl
file in the current working directory, if it exists. -
A
terragrunt.hcl.json
file in the current working directory, if it exists. -
If none of these are found, exit with an error.
Refer to the following pages for a complete reference of supported features in the terragrunt configuration file:
Configuration parsing order
Section titled âConfiguration parsing orderâIt is important to be aware of the terragrunt configuration parsing order when using features like locals and dependency outputs, where you can reference attributes of other blocks in the config in your inputs
. For example, because locals
are evaluated before dependency
blocks, you cannot bind outputs from dependency
into locals
. On the other hand, for the same reason, you can use locals
in the dependency
blocks.
Currently terragrunt parses the config in the following order:
-
include
block -
locals
block -
Evaluation of values for
iam_role
,iam_assume_role_duration
,iam_assume_role_session_name
, andiam_web_identity_token
attributes, if defined -
dependencies
block -
dependency
blocks, including callingterragrunt output
on the dependent units to retrieve the outputs -
Everything else
-
The config referenced by
include
-
A merge operation between the config referenced by
include
and the current config.
Blocks that are parsed earlier in the process will be made available for use in the parsing of later blocks. Similarly, you cannot use blocks that are parsed later earlier in the process (e.g you canât reference dependency
in locals
, include
, or dependencies
blocks).
Note that the parsing order is slightly different when using the --all
flag of the run
command. When using the --all
flag, Terragrunt parses the configuration twice. In the first pass, it follows the following parsing order:
-
include
block of all configurations in the tree -
locals
block of all configurations in the tree -
dependency
blocks of all configurations in the tree, but does NOT retrieve the outputs -
terraform
block of all configurations in the tree -
dependencies
block of all configurations in the tree
The results of this pass are then used to build the dependency graph of the units in the stack. Once the graph is constructed, Terragrunt will loop through the units and run the specified command. It will then revert to the single configuration parsing order specified above for each unit as it runs the command.
This allows Terragrunt to avoid resolving dependency
on units that havenât been applied yet when doing a clean deployment from scratch with run --all apply
.
When multiple units, each with their own terragrunt.hcl
file exist in child directories of a single parent directory, that parent directory becomes a stack.
New to stacks? For a comprehensive introduction to the concept, see our Stacks guide.
What is a terragrunt.stack.hcl file?
Section titled âWhat is a terragrunt.stack.hcl file?âA terragrunt.stack.hcl
file is a blueprint that defines how to generate Terragrunt configuration programmatically.
It tells Terragrunt:
- What units to create.
- Where to get their configurations from.
- Where to place them in the directory structure.
- What values to pass to each unit.
The Two Types of Blocks
Section titled âThe Two Types of Blocksâunit
blocks - Define Individual Infrastructure Components
Section titled âunit blocks - Define Individual Infrastructure Componentsâ- Purpose: Define a single, deployable piece of infrastructure.
- Use case: When you want to create a single piece of isolated infrastructure (e.g. a specific VPC, database, or application).
- Result: Generates a single
terragrunt.hcl
file in the specified path.
stack
blocks - Define Reusable Infrastructure Patterns
Section titled âstack blocks - Define Reusable Infrastructure Patternsâ- Purpose: Define a collection of related units that can be reused.
- Use case: When you have a common, multi-unit pattern (like âdev environmentâ or âthree-tier web applicationâ) that you want to deploy multiple times.
- Result: Generates another
terragrunt.stack.hcl
file that can contain more units or stacks.
Comparison: unit vs stack blocks
Section titled âComparison: unit vs stack blocksâAspect | unit block | stack block |
---|---|---|
Purpose | Define a single infrastructure component | Define a reusable collection of components |
When to use | For specific, one-off infrastructure pieces | For patterns of infrastructure pieces that you want provisioned together |
Generated output | A directory with a single terragrunt.hcl file | A directory with a terragrunt.stack.hcl file |
The Complete Workflow
Section titled âThe Complete Workflowâ- Author: Write a
terragrunt.stack.hcl
file withunit
and/orstack
blocks. - Generate: Run
terragrunt stack generate
to create the actual units*. - Deploy: Run
terragrunt stack run apply
to deploy all units**.
* Multiple commands (like stack run
or run --all
) automatically generate units from terragrunt.stack.hcl
files for you.
** You can also just use run --all apply
to deploy all units in the stack.
Example: Simple Stack with Units
Section titled âExample: Simple Stack with Unitsâunit "vpc" { source = "git::git@github.com:acme/infrastructure-catalog.git//units/vpc?ref=v0.0.1" path = "vpc" values = { vpc_name = "main" cidr = "10.0.0.0/16" }}
unit "database" { source = "git::git@github.com:acme/infrastructure-catalog.git//units/database?ref=v0.0.1" path = "database" values = { engine = "postgres" version = "13"
vpc_path = "../vpc" }}
Running terragrunt stack generate
creates:
- terragrunt.stack.hcl
Directory.terragrunt-stack
Directoryvpc
- terragrunt.hcl
- terragrunt.values.hcl
Directorydatabase
- terragrunt.hcl
- terragrunt.values.hcl
Example: Nested Stack with Reusable Patterns
Section titled âExample: Nested Stack with Reusable Patternsâstack "dev" { source = "git::git@github.com:acme/infrastructure-catalog.git//stacks/environment?ref=v0.0.1" path = "dev" values = { environment = "development" cidr = "10.0.0.0/16" }}
stack "prod" { source = "git::git@github.com:acme/infrastructure-catalog.git//stacks/environment?ref=v0.0.1" path = "prod" values = { environment = "production" cidr = "10.1.0.0/16" }}
The referenced stack might contain:
unit "vpc" { source = "git::git@github.com:acme/infrastructure-catalog.git//units/vpc?ref=v0.0.1" path = "vpc" values = { vpc_name = values.environment cidr = values.cidr }}
unit "database" { source = "git::git@github.com:acme/infrastructure-catalog.git//units/database?ref=v0.0.1" path = "database" values = { environment = values.environment
vpc_path = "../vpc" }}
For more information on these configuration blocks, see:
These special configurations are used by the stack generate command (and all the other stack
prefixed commands) to generate units programmatically, on demand. The units they generate are valid unit configurations, and can be read and used as if they were manually authored.
Included Configurations
Section titled âIncluded ConfigurationsâWhen configurations are included via the include configuration block, Terragrunt expects configurations to be valid unit configurations.
Generally speaking, any HCL file found in a Terragrunt project that isnât named terragrunt.hcl
, terragrunt.stack.hcl
or .terraform.lock.hcl
is expected to be partial unit configurations that will be included by a Terragrunt unit.
Formatting HCL files
Section titled âFormatting HCL filesâYou can rewrite the HCL files to a canonical format using the hclfmt
command built into terragrunt
. Similar to tofu fmt
, this command applies a subset of the OpenTofu/Terraform language style conventions, along with other minor adjustments for readability.
By default, this command will recursively search for hcl files and format all of them for a given stack. Consider the following file structure:
Directoryroot
- root.hcl
Directoryprod
- terragrunt.hcl
Directorydev
- terragrunt.hcl
Directoryqa
- terragrunt.hcl
Directoryservices
- services.hcl
Directoryservice01
- terragrunt.hcl
If you run terragrunt hcl fmt
at the root
, this will update:
-
root/root.hcl
-
root/prod/terragrunt.hcl
-
root/dev/terragrunt.hcl
-
root/qa/terragrunt.hcl
-
root/qa/services/services.hcl
-
root/qa/services/service01/terragrunt.hcl
You can set --diff
option. terragrunt hcl fmt --diff
will output the diff in a unified format which can be redirected to your favourite diff tool. diff
utility must be presented in PATH.
Additionally, thereâs a flag --check
. terragrunt hcl fmt --check
will only verify if the files are correctly formatted without rewriting them. The command will return exit status 1 if any matching files are improperly formatted, or 0 if all matching .hcl
files are correctly formatted.
You can exclude directories from the formatting process by using the --exclude-dir
flag. For example, terragrunt hcl fmt --exclude-dir=qa/services
.
If you want to format a single file, you can use the --file
flag. For example, terragrunt hcl fmt --file qa/services/services.hcl
.