Config file
Config files specify how Infracost should be run on a repo with multiple Terraform projects, such as infrastructure mono repos or Terragrunt repos. Terraform var files/values should also be specified in config files so Infracost knows how to apply them.
Your repo's project list is dynamically generated in CI/CD just before Infracost runs. The costs for the projects are combined into one pull request comment and shown together in Infracost Cloud.
If you have any questions or need help writing a config file, please join our community Slack channel, we'll help you very quickly π
Overviewβ
This section provides an overview of how config files work using an example infrastructure repo. This simple application has the following directory structure.
βββ environment
β βββ dev.tfvars
β βββ staging.tfvars
β βββ legacy.tfvars
β βββ prod.tfvars
βββ modules
β βββ ... # terraform modules
βββ main.tf # the root Terraform module for repo
As you can see above, each Terraform var file stored under the environment
folder corresponds to a different project. The dev
, staging
and prod
environments are all active, however, the legacy
environment is no longer active, so we do not want Infracost to run on it.
A config file for this application is shown below. Line 3 shows how we can loop over the environments and generate a project for each one. The $project._path
variable on line 8 is a special variable that returns the full path of the pattern matched on.
version: 0.1
projects:
{{- range $project := matchPaths "environment/:env.tfvars" }}
{{- if ne $project.env "legacy"}}
- path: .
name: {{ $project.env }}
terraform_var_files:
- {{ $project._path }}
{{- end}}
{{- end }}
Now we will use the infracost generate config
command to generate an infracost.yml
file and use that to run infracost breakdown
as shown below:
$ infracost generate config --repo-path=. \
--template-path=infracost.yml.tmpl \
--out-file=infracost.yml
$ cat infracost.yml
version: 0.1
projects:
- path: .
name: dev
terraform_var_files:
- environment/dev.tfvars
- path: .
name: staging
terraform_var_files:
- environment/staging.tfvars
- path: .
name: prod
terraform_var_files:
- environment/prod.tfvars
$ infracost breakdown --config-file=infracost.yml \
--format=json \
--out-file=infracost-base.json
We'll explain where you can store the infracost.yml.tmpl
template file next. There is no need to store the generated config file. With the template, we'll get cost estimates for all the current environments in the application. Furthermore, this template adds a project for any new environments that are added, so we don't have to change anything π
Usageβ
To add a config file for your repos:
Use the
infracost generate config
command (shown above) when you are writing a config file to test that it generates your project list correctly.The examples section shows common examples you should use as a starting point. The project parameters and the template syntax sections show the full list of options supported by config files.
Once you are happy with the generated project list, go to Infracost Cloud > Repos > my-repo > Settings page. Paste your config file there and click on Save.
You can also store the
infracost.yml.tmpl
file in the root of your repo. This is useful if you do not use Infracost Cloud, or prefer to keep config files in your repos. The config file in Infracost Cloud takes precedence over the repo root file.If you use the Infracost GitHub App or the GitLab App, your config file from Infracost Cloud or the repo root is automatically used. Go to the Repos page and click on the default branch costs, click on the "Re-run estimate" button and wait for it to update the page. You should now see your project list from the generated config file.
If you do not use the GitHub App or GitLab App, in your CI/CD pipeline run the
infracost generate config
command followed by theinfracost breakdown
anddiff
commands with the--config-file
flag pointing to the generated config file (as shown in the above overview section).If you have many repos with a similar directory structure, you can define a default config file to be used by all of your repos from the Org Settings > Default repo config file page. This config file can be overridden on a per-repo basis from the Repos > my-repo > Settings page, or by adding an
infracost.yml.tmpl
to the repo root. This enables you to add many repositories to Infracost quickly.
Examplesβ
Looping over projects with environments contained in a sub folder
version: 0.1
projects:
{{- range $project := matchPaths "environment/:app/:env" }}
- path: {{ $project._dir }}
name: {{ $project.app }}-{{ $project.env }}
{{- end }}
Excluding certain projects
version: 0.1
projects:
{{- range $project := matchPaths "environment/:env.tfvars" }}
{{- if ne $project.env "legacy"}}
- path: {{ $project._dir }}
name: {{ $project.env }}
terraform_var_files:
- {{ $project._path }}
{{- end}}
{{- end }}
Only matching certain project
version: 0.1
projects:
{{- range $project := matchPaths "environment/:env(prod|dev).tfvars" }}
- path: {{ $project._dir }}
name: {{ $project.env }}
terraform_var_files:
- {{ $project._path }}
{{- end }}
Looping over multiple projects with a var file contained at the root level as well as project
version: 0.1
projects:
{{- range $project := matchPaths ":name/:region/main.tf" }}
- path: {{ $project.name }}/{{ $project.region }}
name: {{ $project.name }}-{{ $project.region }}
terraform_var_files:
- local.tfvars
{{- if pathExists "." "global.tfvars"}}
- {{ relPath $project._dir "global.tfvars" }}
{{- end}}
{{- end }}
Project with configuration defined in a non-Terraform file
version: 0.1
projects:
{{- $envs := list "prod" "dev"}}
{{- range $project := matchPaths ":app/main.tf" }}
{{- range $env := $envs}}
- path: {{ $project._path }}
name: {{ $project.app }}-{{ $env }}
{{- end }}
{{- end }}
Looping over projects with complexΒ `matchPaths`Β matchers
// Example folder structure:
.
βββ dev
βββ prod
βββ test
βββ foo
// Ensure a folder matches a list of names, ignore everything else
{{- range $match := matchPaths ":env(dev|prod|test)" }}
// Returns:
[{env: dev}, {env: prod}, {env: test}]
---
Example folder structure:
.
βββ foo/
β βββ main.tf
βββ bar/
βββ dev/
β βββ main.tf
βββ prod/
βββ main.tf
// Match a nested folder if it exists
{{- range $match := matchPaths ":app/:env?/main.tf" }}
// Returns:
[{app: foo}, {app: bar, env: dev}, {app: bar, env: prod}]
---
Example folder structure:
.
βββ foo/
β βββ prod.tfvars
β βββ prod-euwest.tfvars
βββ bar/
βββ dev.tfvars
// Match a region in the tfvar name if it exists, and capture it
{{- range $match := matchPaths ":app/:env{-:region}?.tfvars" }}
// Returns:
// [{app: foo, env: prod}, {app: foo, env: prod, region: euwest}, {app: bar, env: dev}]
Project parametersβ
The following table shows the parameters each project
can have in the config file:
Parameter | Description |
---|---|
path | Required. String. Path to the Terraform directory. The path is relative to the working directory you run infracost from. A path can be repeated with different parameters, e.g. for multiple Terraform var files. |
name | Optional. String. Defaults to code path, workspace or Terraform/Terragrunt module within a repo. Name of project to use in all outputs (pull request comment, Infracost Cloud and CLI). |
terraform_var_files | Optional. Array of string. Variable files to use when parsing Terraform HCL code, similar to Terraform's -var-file flag. Files with the .auto.tfvars extension do not need to be added to the list as they are processed automatically by Infracost. The file paths are relative to the path of the project. For example:
|
terraform_vars | Optional. Map of strings. Input variables to use when parsing the Terraform HCL code, similar to Terraform's -var flag. For example:
|
dependency_paths | Optional. Only applicable for GitHub App and GitLab App users. Array of strings. Array of file or directory paths that should trigger project estimates. If this is specified, code changes to the path target will NOT trigger cost estimates unless the path is included in dependency_paths . All paths are relative to the working directory of your infracost.yml file. Supports glob patterns, for example:
|
usage_file | Optional. String. Path to Infracost usage file that specifies values for usage based resources. The path is relative to the working directory you run infracost from. |
exclude_paths | Optional. Array of strings. Array of file or directory paths to exclude from evaluation, relative to path of project. Supports glob patterns too, for example:
|
include_all_paths | Optional. Boolean. Defaults to false meaning that Infracost will autodetect only root Terraform modules. Setting this to true forces the autodetect function to estimate all directories (i.e. root and non-root modules) with valid project files, down to a max depth of 10 directories. |
env | Optional. Map of strings. Environment variables that are passed to the project during processing. Also supports referencing existing environment variables using the syntax ${MY_ENV_VAR} . Environment variables that start with INFRACOST_ are global in scope (not per-project) and cannot be used inside this parameter. For example:
|
terraform_workspace | Optional. String. Used to set the Terraform workspace. Only set this for multi-workspace repos, otherwise it might result in the Terraform error "workspaces not supported". |
terraform_cloud_workspace | Optional. String. For Terraform Cloud/Enterprise users. Used to set the Terraform Cloud workspace. Only set this if your local workspace name differs from your cloud workspace, and you do not already have a Terraform Cloud block defining the remote workspace name (e.g. using `prefix`). |
terraform_cloud_org | Optional. String. For Terraform Cloud/Enterprise users. Used to set the Terraform Cloud organization. Only set this if you do not already have a Terraform Cloud block that defines your Terraform cloud organization name. |
Template syntaxβ
Config file templates, like Helm templates, are built on top of Golang's text/template engine, offering an expressive way to write templates. Below we'll describe the template syntax and brief explanation of the main expressions and logic.
Syntaxβ
Templates use a pair of curly braces {{ }}
to delimit actions, such as variables
, if/else
statements, and range
iterations. Within the curly braces, Infracost can recognize and execute template actions.
For example, {{ $project.name }}
would print the value of the $project.name
, while
{{- if .Enabled }}
Enabled
{{- else }}
Disabled
{{- end }}
would execute conditional logic based on the value of the Enabled
field in the current context.
if/else
β
Conditional logic can be added to templates using the {{ if }}
, {{ else if }}
, and {{ else }}
keywords. The logical operators and
and or
can also be used, for example
{{- if .testA }}
testA is true
{{- else if and .testB .testC }}
testB and testC is true
{{- else }}
Disabled
{{- end }}
This can be useful to conditionally include projects for Infracost to evaluate, for example:
{{- if ne $project.name "test" }}
- path: .
...
{{- end }}
adds a configuration entry for the current project if it does not equal "test".
range
β
Templates can iterate over arrays and maps using the {{ range }}
keyword. For example:
{{- range .Items }}
{{- .Name }}
{{- end }}
would print the value of the Name
field for each item in the Items
array in the current context. Within config file templates range
expressions are normally combined with matchPaths
calls to iterate over a subset of directories or files, for example:
{{- range $project := matchPaths "environment/:env/terraform.tfvars" }}
- path: .
name: {{ $project.env }}
{{- end }}
sets successive elements returned from matchPaths
to $project
, which can be accessed inside the range
loop, e.g. $project.env
Global variablesβ
Templates have access to the following global variables:
.Branch
- The name of the current branch that the template is executed on.
The following global variables are only available in CI:
.BaseBranch
- The name of the base branch that the pull request is being merged into (which is usually main or master).{{ if eq .BaseBranch "production" }}
- path: terraform/infra/prod
name: infra-prod
{{ end }}
Functionsβ
Config file templates support a wide range of built-in functions to make it easy for you to write config files that work for your project structure. Below you'll find a list of supported functions with detailed examples.
Please be aware that the functions and examples provided are designed for a Unix-based system. If you are using Windows, make sure to adjust the path syntax accordingly. For instance, use backslashes
\
in paths as per Windows system requirements.
Filepath functionsβ
Config file templates include the following functions to help you traverse your project structure:
matchPaths
β
Returns a list of matches that in the project directory tree that match the pattern.
Arguments:β
name | description | example |
---|---|---|
pattern | a path pattern to one or more files or directories in your project. Keys that you wish to extract must be prefixed with ':' | "environment/:env/terraform.tfvars" , "infra/:env/:app" , "environment/:app/:env.tfvars" , ":optional-parent?/:optional-child?/main.tf" |
Returns:β
A collection of matches in the current project. Results are returned with a map of extracted keys from the pattern. In addition, each result has two additional properties:
_path
- the full path of that the pattern matched on_dir
- the base directory that the pattern matched on
Example:β
- Template usage
- Directory tree
- Output
Using the range
expression to iterate over the results like so:
version: 0.1
projects:
{{- range $project := matchPaths "environment/:env/terraform.tfvars" }}
- path: .
name: {{ $project.env }}
terraform_var_files:
- {{ $project._path }}
{{- end }}
βββ environment
β βββ dev
β β βββ terraform.tfvars
β βββ prod
β βββ terraform.tfvars
βββ infracost.yml.tmpl
βββ main.tf
version: 0.1
projects:
- path: .
name: dev
terraform_var_files:
- environment/dev/terraform.tfvars
- path: .
name: prod
terraform_var_files:
- environment/prod/terraform.tfvars
pathExists
β
Returns true if the path exists within base.
Argumentsβ
name | description | example |
---|---|---|
base | The directory to search for the given file or directory. Use "." to start from the project root. | "." , "some/dir" |
path | The path of the file or directory to search for. This must be relative to the base path provided at argument one. | "dir/to/find" , "file/to/find.txt" |
Exampleβ
- Template
- Directory tree
- Output
version: 0.1
projects:
{{- range $project := matchPaths "environment/:env/terraform.tfvars" }}
{{- if pathExists $project._dir "include.txt" }}
- path: .
name: {{ $project.env }}
{{- end }}
{{- end }}
βββ environment
β βββ dev
β β βββ include.txt
β β βββ terraform.tfvars
β βββ prod
β βββ terraform.tfvars
βββ infracost.yml.tmpl
βββ main.tf
version: 0.1
projects:
- path: .
name: dev
isDir
β
Returns true if the path is a directory.
Argumentsβ
name | description | example |
---|---|---|
path | The path to check | "." , "some/dir" |
Exampleβ
- Template
- Directory tree
- Output
version: 0.1
projects:
{{- range $project := matchPaths "environment/:env" }}
{{- if isDir $project._path }}
- path: $project._path
name: {{ $project.env }}
{{- end }}
{{- end }}
βββ environment
β βββ dev
β β βββ main.tf
β βββ prod
β β βββ main.tf
β βββ config.yml
βββ infracost.yml.tmpl
version: 0.1
projects:
- path: environment/dev
name: dev
- path: environment/prod
name: prod
readFile
β
Reads the file at the given directory, this can then be printed into the template or passed to one of the parseYaml
or parseJson
functions to allow for data manipulation.
Argumentsβ
name | description | example |
---|---|---|
path | The path of the file relative to the location of the config file. | "some/file.json" |
parseYaml
β
Decode the contents of a string as a YAML structure.
Argumentsβ
name | description | example |
---|---|---|
contents | The YAML string to decode, this is normally obtained by loading a file using the readFile function. | (readFile "some/file.yaml") |
Exampleβ
- Template
- Directory tree
- Output
version: 0.1
{{- $yaml := parseYaml (readFile "config/env.yaml") }}
projects:
- path: infra
name: my-infra
env:
{{- range $key, $value := $yaml.envs }}
{{ $key }}: {{ $value }}
{{- end }}
βββ config
β βββ env.yaml
βββ infra
βββ main.tf
version: 0.1
projects:
- path: infra
name: my-infra
env:
foo: bar
baz: bat
parseJson
β
Decode the contents of a string as a JSON object.
Argumentsβ
name | description | example |
---|---|---|
contents | The JSON string to decode, this is normally obtained by loading a file using the readFile function. | (readFile "some/file.json") |
Exampleβ
- Template
- Directory tree
- Output
version: 0.1
{{- $json := parseJson (readFile "config/env.json") }}
projects:
- path: infra
name: my-infra
env:
{{- range $key, $value := $json.envs }}
{{ $key }}: {{ $value }}
{{- end }}
βββ config
β βββ env.json
βββ infra
βββ main.tf
version: 0.1
projects:
- path: infra
name: my-infra
env:
foo: bar
baz: bat
relPath
β
Returns the relative path of the target path from the given base path.
This is useful for providing the correct relative path for shared variable files that exist outside of the project path.
Argumentsβ
name | description | example |
---|---|---|
base | The base path that the resulting relative path is computed against | "." , "some/dir" |
target | The target path, relative to the repo root directory | "global.tfvars" |
Exampleβ
- Template
- Directory tree
- Output
version: 0.1
projects:
{{- range $project := matchPaths "environment/:env" }}
- path: $project._path
name: {{ $project.env }}
terraform_var_files:
{{ relPath $project.path "global.tfvars" }}
{{- end }}
βββ environment
β βββ dev
β β βββ main.tf
β βββ prod
β βββ main.tf
βββ global.tfvars
version: 0.1
projects:
- path: environment/dev
name: dev
terraform_var_files:
- ../../global.tfvars
- path: environment/prod
name: prod
- ../../global.tfvars
base
β
Returns the last element of path, for example:
base "full/path/here.txt"
returnshere.txt
base "full/path"
returnspath
ext
β
Returns the file name extension used by path, for example:
ext "full/path/here.txt"
returns.txt
stem
β
Returns the last element of path with the extension removed, for example:
stem "full/path/here.txt"
returnshere
Control flow functionsβ
Config file templates support control flow functions including eq
, ne
and not
. Templates can also use the control flow functions lt
, le
, gt
, ge
, and
and or
from the base text/template library. The documentation for these additional functions can be found here.
eq
β
Returns the boolean truth of arg1 == arg2, for example:
eq $project.arg1 $project.arg2
ne
β
Returns the boolean truth of arg1 != arg2, for example:
ne $project.arg1 $project.arg2
not
β
Returns the boolean negation of its single argument, for example:
not (pathExists "path")
String Functionsβ
Config file templates support for the following string manipulation functions startsWith
, endsWith
and contains
. Templates can also use the string functions print
, printf
and println
from the base text/template library. The documentation for these additional functions can be found here.
startsWith
β
Tests whether the string begins with prefix, for example:
startsWith "mystring" "my"
returns truestartsWith "mystring" "foo"
returns false
endsWith
β
Tests whether the string ends with suffix, for example:
endsWith "mystring" "string"
returns trueendsWith "mystring" "foo"
returns false
contains
β
Reports whether the substring is within the subject, for example:
contains "mystringbar" "string"
returns trueendsWith "mystringbar" "foo"
returns false