# 4) Variables, tfvars & Outputs (20 min) In this section, you’ll **parameterize** your Terraform configuration so it’s flexible across environments (like *dev* and *prod*) and learn how to **print useful values** after deployment. ## Why variables and tfvars? - **Variables** let you avoid hard‑coding values (e.g., instance type, names). - **.tfvars files** store a specific set of variable values for each environment. You can switch environments quickly without editing code. - **Outputs** print important information (IDs, IPs, AZs) for later use in scripts, CD pipelines, or as inputs to other modules. ## Step 1: Create a working directory ```bash mkdir -p ~/terraform-vars-lab && cd ~/terraform-vars-lab ``` Creates a clean folder for this exercise and moves into it. ## Step 2: Define variables Create a file **variables.tf**: ```hcl variable "instance_type" {} variable "instance_name" {} ``` - Declares two variables, `instance_type` and `instance_name`. - No defaults are provided, so Terraform will expect values (either via `-var` flags, `.tfvars` files, or prompts). > Tip: You can add descriptions and types to make your code self-documenting: > ```hcl > variable "instance_type" { type = string, description = "EC2 size, e.g. t2.micro" } > variable "instance_name" { type = string, description = "Tag: Name for the instance" } > ``` ## Step 3: Write the main configuration Create **main.tf**: ```hcl provider "aws" { region = "ap-south-1" } resource "aws_instance" "ec2_instance" { ami = "ami-0e6329e222e662a52" instance_type = var.instance_type tags = { Name = var.instance_name } } ``` - **provider "aws"**: points Terraform to AWS in the Mumbai region. - **resource "aws_instance" "ec2_instance"**: creates an EC2 instance. - `ami`: the base OS image (Amazon Linux 2 for ap-south-1). - `instance_type`: references your variable using `var.instance_type`. - `tags`: uses `var.instance_name` so the tag can change per environment. ## Step 4: Expose useful outputs Create **outputs.tf**: ```hcl output "instance_id" { value = aws_instance.ec2_instance.id } output "public_ip" { value = aws_instance.ec2_instance.public_ip } output "availability_zone" { value = aws_instance.ec2_instance.availability_zone } ``` - After apply, Terraform will print these values. - Great for quickly finding the instance or for handing values to other tools. > Tip: Add `sensitive = true` to hide secrets in logs: > ```hcl > output "db_password" { value = var.db_password, sensitive = true } > ``` ## Step 5: Create environment files (tfvars) Create **dev.tfvars**: ```hcl instance_type = "t2.micro" instance_name = "Dev-Instance" ``` Create **prod.tfvars**: ```hcl instance_type = "t3.micro" instance_name = "Prod-Instance" ``` - These files define different values for the *same* variables. - You can add more environments (e.g., `test.tfvars`, `staging.tfvars`) as needed. > Tip: Keep environment files in version control, but never commit secrets. For secrets, use a secure tool (e.g., AWS SSM Parameter Store, Vault) or CI/CD‑controlled variables. ## Step 6: Initialize, apply, output, and switch environments ```bash terraform init ``` - Downloads provider plugins and prepares the working directory. ```bash terraform apply -var-file="dev.tfvars" -auto-approve ``` - Applies with **dev** values. - Creates a `t2.micro` instance named **Dev-Instance**. ```bash terraform output ``` - Prints the values from **outputs.tf** to the terminal (instance id, public IP, AZ). ```bash terraform destroy -auto-approve ``` - Destroys the **dev** instance to avoid charges before testing **prod**. ```bash terraform apply -var-file="prod.tfvars" -auto-approve ``` - Applies with **prod** values. - Creates a `t3.micro` instance named **Prod-Instance**. ```bash terraform output -json > output.json cat output.json ``` - Exports outputs in **JSON** format, perfect for automation pipelines. - `output.json` can be parsed by scripts or downstream systems. ## Common gotchas & best practices - **Keep AMIs per region**: AMI IDs are region‑specific. If you change regions, update the AMI. - **Validate before apply**: Run `terraform validate` and `terraform plan` to catch mistakes early. - **Naming**: Tags are your friend. Use `Name` tags consistently so you can find resources fast. - **Separate state**: For real projects, use separate state/workspaces or remote backends (S3 + DynamoDB) per environment. ## Wrap-Up You now know how to: - Declare variables and pass values with `.tfvars` - Reuse the same code for **multiple environments** - Surface key information using **outputs** - Export outputs to **JSON** for automation This pattern is the backbone of scalable Terraform projects.