> ## Content Index
> Fetch the complete content index at: https://www.jeremyjordan.me/llms.txt
> Use this file to discover other available public pages before exploring further.

# Terraform configuration: quick reference
- URL: https://www.jeremyjordan.me/terraform-quick-reference/
- Published: 2022-07-27T04:36:50.000Z
- Updated: 2023-03-05T03:27:40.000Z
- Description: This page contains a quick reference for writing Terraform configuration.
- Author: Jeremy Jordan
- Tags: Machine Learning

This page contains a quick reference for writing Terraform configuration. For a conceptual introduction to Terraform and managing your infrastructure as code, read [this blog post](https://www.jeremyjordan.me/terraform).

*Disclaimer: for the most up-to-date and detailed information, check out the official Terraform documentation.*

[Overview - Configuration Language | Terraform by HashiCorpYou can use the Terraform language to write configuration files that tell Terraform how to manage a collection of infrastructure.![](https://www.terraform.io/favicon.ico)Terraform by HashiCorp![](https://www.terraform.io/img/og-image.png)](https://www.terraform.io/language?ref=jeremyjordan.me)

*Jump to:*

- [Configuration blocks](#configuration)  
  - [Terraform](#terraform)
  - [Provider](#provider)
  - [Resource](#resource)
  - [Variable](#variable)
  - [Output](#output)
  - [Module](#module)
  - [Data](#data)
  - [Locals](#locals)
- [Dynamic expressions](#expressions)  
  - [Conditional statements](#conditionals)
  - [Wildcards](#wildcards)

## Configuration blocks

#### Terraform

Configuration block that allows you to specify various Terraform settings (such as required versions for Terraform and/or its providers).

```text
terraform {
  required_providers {
    # e.g. include the AWS provider and require a specific major version
    aws = {
      source  = "hashicorp/aws"
      version = ">= 4.0.0, < 5.0.0"
    }
  }
  required_version = ">= 1.2.3"
}

```

#### Provider

Versioned code which is used to communicate with an external infrastructure provider. 

```text
provider "provider_name" {
  # provider-specific configuration
  # e.g. what region should this provider create your resources in?
} 

```

#### Resource

Smallest unit of infrastructure managed by a provider. 

```text
resource "resource_type" "resource_name" {
  # resource-specific configuration
}

```

- The `resource_type` always starts with the prefix `{provider}_`
- You can reference a given resource in other parts of your Terraform configuration using the format `{resource_type}.{resource_name}`
- There's a small set of meta-arguments which you can use for any resource:  
  - `count`: create multiple instances of the same resource specification
  - `for_each`: configure a set of resources based on a provider iterable
  - `provider`: override the default provider configuration (e.g. changing the region to deploy a specific resource)
  - `depends_on`: specify hidden dependencies between resources that Terraform isn't able to infer
  - `lifecycle`: configuration around resource lifecycle management (e.g. create a new version of the resource before destroying the old one)

#### Variable

Allow end users to specify values (to be used in resource creation) when defining a module.

```text
variable "variable_name" {
  type        = string
  description = ""
  
  # optional
  default     = ""
  sensitive   = true
  validation {
    condition     = ...
    error_message = ""
  }
}

```

- Usually defined in a separate file, `variables.tf`, for readability
- These values are constant, they cannot be changed during planning or execution
- You can reference a given variable as `var.{variable_name}`
- Supported types:  
  - simple (`string`, `bool`, `number`)
  - collection (`map`, `list`, `set`)
  - structural (`tuple`, `object`)
- You can optionally add one or more validation conditions (e.g. to make sure a resource matches AWS resource naming requirements). This can be helpful for ["failing fast"](https://scalefactory.com/blog/2021/10/13/failing-faster-with-terraform/?ref=jeremyjordan.me) when you provide improper values.
- By default, variables are **not** treated as sensitive. You can specify `sensitive = true` in order to prevent Terraform from outputing these values to the console.

#### Output

Expose a specific attribute of a resource within a module.

```text
output "output_name" {
  description = ""
  value       = resource_type.resource_name.attribute
  
  # optional
  sensitive   = true
  precondition {
    condition     = ...
    error_message = ""
  }
}

```

- Usually defined in a separate file, `outputs.tf`, for readability
- You can reference a module's output as `{module_name}.{output_name}`
- You can optionally add one or more preconditions to check before returning an output value (e.g. to check that a certificate status is set to `ISSUED`). This can be used as a last line of defense to validate your assumptions before returning data about a given resource.
- By default, variables are **not** treated as sensitive. You can specify `sensitive = true` in order to prevent Terraform from outputing these values to the console.

#### Module

A logical grouping of resources which can be configured and deployed together.

```text
module "module_name" {
  source          = "../path/to/module"
  
  # optional
  version = ""
}

```

- Encourages reuse of configuration and provides consistency across your infrastructure stack
- There’s a small set of universal “meta-arguments” that you can use for any module:  
  - `count`: create multiple instances of the same module specification
  - `for_each`: configure a set of modules based on a provider iterable
  - `provider`: override the default provider configuration (e.g. changing the region to deploy the resources in your module)
  - `depends_on`: specify hidden dependencies between your module and other resources that Terraform isn't able to infer
- Modules can be referenced from local filepaths or remote repositories (Terraform registry, Github, S3)

In addition to using existing modules available on the Terraform registry, you can also define your own. A module can be defined as a set of Terraform configuration files within a single directory.

```text
.
├── LICENSE
├── README.md
├── main.tf
├── variables.tf
├── outputs.tf

```

 An example Terraform module definition.

#### Data

Retrieve information from an external infrastructure provider.

```text
data "data_resource_type" "data_resource_name" {
  # parameters used to retrieve information
}

```

#### Locals

Used to provide a succinct or readable name for a Terraform expression which may be referenced multiple times.

```text
locals {
  # e.g. define a set of required tags to add to all resources
  required_tags = {
    project     = var.project_name,
    environment = var.environment
  }
  tags = merge(var.resource_tags, local.required_tags)
  
  # e.g. define a common suffix for use in multiple resource definitions
  name_suffix = "${var.project_name}-${var.environment}"
}

```

- Can be referenced as `locals.{attribute}`
- Dynamic expressions (e.g. using Terraform functions) are allowed, providing more flexibility than you have available in Terraform variables
- It's recommended you use locals sparringly, keeping in mind the trade-offs between readability and DRY principles  
  - In other words, don't make someone constantly scroll up to the `locals` block in order to figure out how a given resource is being configured

## Dynamic expressions

#### Conditional statements

You can express conditional statements in Terraform, although I find the syntax a bit odd.

```text
attribute  = (conditional_expression ? value_if_true : value_if_false)

```

Interpret `?` as “then” and `:` as “else” when reading.

The `conditional_expression` itself is defined with common syntax:

| Symbol | Meaning   |
| ------ | --------- |
| !=     | not equal |
| \==    | equal     |

#### Wildcards

You can use a splat `*` expression to reference a given attribute over a list of resources.

```text
resource "aws_instance" "app_servers" {
  count = 5
  ...
}

output "private_addresses" {
  value = aws_instance.app_servers[*].private_dns
}

```

#### Comprehensions

You can create lists and maps using syntax similar to list/dictionary comprehensions in Python.

The general syntax is `[for item in iterable: value]` for a list and `{for item in iterable: key => value}` for a map. You can also add conditional statements, such as in the example below.

```
locals {
  tags = tomap({ foo = "123", bar = "456", empty = "" })
}

value = { for key, value in local.tags : key => value if value != "" }

```