Terraform - Code Structure
Tags: terraform
Published: 2021-07-12 16:25:27

---
title: Terraform - Code Structure
published: true
date: 2021-07-12 16:22:16 UTC
tags: Terraform
canonical_url: https://blog.g33kzone.com/terraform-code-structure
cover_image: https://cdn.hashnode.com/res/hashnode/image/upload/v1626073210537/hrWwZkiFk.png
series: terraform
---

The previous Terraform [blog](https://dev.to/g33kzone/terraform-getting-started-26d1) gave us a basic introduction to Terraform. We also discussed writing a simple Terraform code to create an AWS EC2 instance with minimal code.

Maintaining all codebases in a single `main.tf` file is good for beginners. However, this approach will lead to maintainability issues as our underlying infrastructure grows. Moreover, in practical situations, you might also need to deal with multiple environments (e.g. DTAP - dev/test/acceptance/production).

Other deciding factors for code modularization are as follows-

- Project Complexity
  - Count of Terraform Providers involved
  - Count of Infra resources to be maintained by Terraform
- Cadence of Infrastructure changes - daily / weekly / monthly
- Deployment Strategy - CI/CD Pipeline, GitOps, etc.

It is recommended to logically split the source code as follows:

- `provider.tf` - contains provider configuration in root module
- `main.tf` - call modules, locals, and data sources to create all resources
- `variables.tf` - contains variable declarations used in `main.tf`
- `outputs.tf` - contains outputs from the resources created in `main.tf`
- `terraform.tfvars` - contains variable definitions to provide default variable values. Terraform will automatically load variables from those files.

Let us refer to the initial Terraform code and understand how we can logically break it down further. ![terraform-getting-started.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1626077688967/dxrLiwZKB.png)

As shown in the above image,

- Red block will be part of `provider.tf`
- Green block will be part of `main.tf`

#### Using Input Variable Values

As we treat Terraform as IaC, we should ensure there are no hardcodings. These must be configured in `variables.tf`. The following block must be defined for every variable.

```terraform
variable "aws_region" {
    type = string
    description = "AWS Region"
# default value is optional.
    default = "us-east-1"
}

```

#### Variables on the Command Line

A default value can be configured (as shown above) for a variable. However, we can override this value while executing the code at runtime.

```bash
terraform apply -var aws_region="eu-west-1"

```

#### Environment Variables

Also, Terraform can search the environment of its own process for environment variables named `TF_VAR_` followed by the name of a declared variable. This can be useful when running Terraform in automation.

```bash
export TF_VAR_aws_region = eu-west-1

```

#### Variable Definitions (.tfvars) Files

For bulk values, it is of convenience to specify their values in a variable definitions file (with a filename ending in either `.tfvars` or `.tfvars.json`)

Terraform also automatically loads a number of variable definitions files if they are present:

- Files named exactly `terraform.tfvars` or `terraform.tfvars.json`.
- Any files with names ending in `.auto.tfvars` or `.auto.tfvars.json`.

This variable can then be used to replace the hardcodings.

```terraform
region = var.aws_region

```

Our code post formatting will look as follows:

![Terraform File Structure.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1626105252916/QVBsFkYTW.png)

### provider.tf

```terraform
terraform {
  required_providers {
    aws = {
      source = "hashicorp/aws"
      version = "~>3.0"
    }
  }
}

provider "aws" {
  region = var.aws_region
  default_tags {
    tags = {
      "Environment" = "dev"
      "Owner" = "g33kzone"
    }
  }
}

```

### variables.tf

```terraform
variable "aws_region" {
    type = string
    description = "AWS Region"
}

variable "instance_type" {
    type = string
    description = "AWS EC2 Instance Type"
}

variable "aws_ec2_ami" {
    type = string
    description = "EC2 AMI for Amazon Linux 2"
}

```

### main.tf

```terraform
resource "aws_instance" "web" {
  instance_type = var.instance_type
  ami = var.aws_ec2_ami

  tags = {
    "Name" = "aws-ec2-demo"
  }
}

```

### terraform.tfvars

```terraform
aws_region = "us-east-1"
instance_type = "t2.micro"
aws_ec2_ami = "ami-04d29b6f966df1537"

```

We are done with the coding. Let us execute this Terraform code with the following commands:

```bash
# open your shell in the same project folder

# download the terraform core components 
# and initialize terraform in this directory
terraform init


# Validate changes to be made in AWS after the execution
terraform plan


# -auto-approve is used to skip manual approval prompt
terraform apply -auto-approve

```

## Very Important

### Clean Up

Do not forget to delete the infrastructure created to avoid incurring any costs.

```bash
# running this command will destroy all the resources
terraform destroy -auto-approve

```

Github Repo - [https://github.com/g33kzone/tf-aws-ec2.git](https://github.com/g33kzone/tf-aws-ec2/tree/modular-beginner)

In future posts, I will delve into Terraform Modules.