Target platform: AWS (us-east-1) · Tool: Terraform Community Edition · Language: HCL (HashiCorp Configuration Language)
Table of Contents
- Introduction to Infrastructure as Code (IaC)
- What is Terraform?
- The Terraform Workflow
- Configuration Files and HCL Syntax
- Deploying Infrastructure
- Input Variables and Output Values
- Expressions, Functions, and Locals
- Terraform State
- Reference Project: Globomantics Web App
- Reference Diagrams
- Reference Tables
- Next Steps
1. Introduction to Infrastructure as Code (IaC)
Definition
Infrastructure as Code: Provisioning infrastructure through software to achieve consistent and predictable environments.
IaC is built on a fundamental principle: every deployment is described in code, not performed manually through a console. This guarantees reproducibility: the same code always produces the same result.
Key concepts of IaC
| Concept | Description |
|---|---|
| Defined in code | Infrastructure is described in files (JSON, HCL, Python, YAML…) |
| Stored in source control | Git + GitHub for versioning, tracking, and collaboration |
| Declarative vs Imperative | You describe the desired state, not the steps to get there |
| Idempotent | Running the same code multiple times always produces the same final state |
| Reusable | The same template can serve for dev, staging, and prod |
Why IaC?
- Eliminates “snowflake servers” (manually configured servers, each one different)
- Enables drift detection: Terraform detects when the real infrastructure differs from the configuration
- Facilitates collaboration: teams work on the same code with Git
- Accelerates environment provisioning from days to minutes
2. What is Terraform?
Terraform is a tool created by HashiCorp to automate the deployment and lifecycle management of infrastructure.
Available editions
| Edition | Description |
|---|---|
| Terraform Community Edition | Free, open-source (Business Source License) — used in this course |
| HCP Terraform | HashiCorp SaaS service (formerly Terraform Cloud) |
| Terraform Enterprise | Self-hosted version of HCP Terraform |
Key characteristics
- Platform-agnostic: AWS, Azure, GCP, VMware, Digital Ocean — any service with an API
- Single binary compiled in Go — no dependencies to install
- Declarative syntax via HCL (or JSON)
- Providers: plugins that bridge Terraform and platform APIs
- State: JSON file that stores the state of deployed infrastructure
Simplified architecture
┌──────────────┐ HCL/JSON ┌──────────────────┐
│ Developer │ ──────────────> │ Terraform Binary │
│ (VS Code) │ │ (terraform.exe) │
└──────────────┘ └────────┬─────────┘
│ Provider Plugin
│ (e.g. hashicorp/aws)
▼
┌──────────────────┐
│ Cloud APIs │
│ (AWS, Azure…) │
└──────────────────┘
3. The Terraform Workflow
The Terraform workflow breaks down into three main phases:
flowchart LR
A([✏️ Write\nWrite HCL code]) --> B([📋 Plan\nPreview changes])
B --> C([🚀 Apply\nApply changes])
C --> D([🔁 Repeat\nModify and iterate])
D --> A
C --> E([💥 Destroy\nTear down environment])
style A fill:#4A90D9,color:#fff
style B fill:#F5A623,color:#fff
style C fill:#7ED321,color:#fff
style D fill:#9B9B9B,color:#fff
style E fill:#D0021B,color:#fff
Phase details
| Phase | Command | Description |
|---|---|---|
| Write | (editing .tf files) | Write or modify HCL configuration files |
| Init | terraform init | Initialize: download providers, prepare state |
| Plan | terraform plan | Generate an execution plan (dry run) |
| Apply | terraform apply | Apply changes to the target environment |
| Destroy | terraform destroy | Destroy all infrastructure managed by the state |
Golden rule: Terraform never makes changes without an execution plan. Predictability is guaranteed.
4. Configuration Files and HCL Syntax
4.1 Structure of .tf Files
Terraform loads all .tf files from the current working directory and combines them in memory to form a configuration. Subdirectories are not automatically included (except via modules).
globo_web_app/
├── main.tf # Main resources
├── variables.tf # Input variable definitions
├── outputs.tf # Output values
├── locals.tf # Computed local values
├── terraform.tf # terraform block (required providers, backend)
├── terraform.tfvars # Variable values (auto-loaded)
└── templates/
└── startup_script.tpl # Template used by templatefile()
Note: File names are human conventions. Terraform assigns no special meaning to the name
main.tf— all that matters is the.tfextension.
4.2 HCL Blocks
Everything in HCL is structured as blocks:
<BLOCK_TYPE> "<LABEL_1>" "<LABEL_2>" {
# Arguments (key = value pairs)
argument_name = expression
# Nested block
nested_block {
nested_argument = "value"
}
}
Concrete example — EC2 resource:
resource "aws_instance" "web_server" {
ami = "ami-0c02fb55956c7d316"
instance_type = "t3.micro"
tags = {
Name = "MyWebServer"
}
}
resource→ block type"aws_instance"→ label 1: resource type (comes from the AWS provider)"web_server"→ label 2: unique local name for referencing this resourceami,instance_type,tags→ arguments
4.3 The 4 Main Block Types
terraform block
Defines configuration metadata: required providers, Terraform version, state backend.
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
# S3 backend (optional — remote state)
backend "s3" {
bucket = "my-terraform-state-bucket"
region = "us-east-1"
key = "globo-web-app/terraform.tfstate"
}
}
provider block
Configures a provider instance (e.g. AWS region, credentials).
provider "aws" {
region = "us-east-1"
# Never put credentials here — use AWS CLI or environment variables
}
⚠️ Security: Never store AWS credentials in a
.tffile that will be committed to Git.
resource block
Defines infrastructure to create and manage. This is the heart of Terraform.
resource "aws_vpc" "app" {
cidr_block = "10.0.0.0/16"
enable_dns_hostnames = true
}
resource "aws_security_group" "nginx_sg" {
name = "nginx_sg"
vpc_id = aws_vpc.app.id # Reference to the VPC above
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
data block
Queries an existing resource (read-only). Equivalent to a resource in “read-only” mode.
# Fetches the latest Amazon Linux 2 AMI via SSM Parameter Store
data "aws_ssm_parameter" "amzn2_linux" {
name = "/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2"
}
# Usage in a resource block:
resource "aws_instance" "nginx1" {
ami = nonsensitive(data.aws_ssm_parameter.amzn2_linux.value)
# ...
}
5. Deploying Infrastructure
5.1 terraform init
Initializes the working directory. Must be run first, and every time a provider or module is added.
terraform init
What init does:
- Downloads the required provider plugins (e.g.
hashicorp/aws) - Creates the
.terraform.lock.hclfile (exact provider versions — commit to Git) - Prepares the state backend
- Downloads referenced modules (if applicable)
Result in the directory:
.terraform/
├── providers/
│ └── registry.terraform.io/hashicorp/aws/5.x.x/...
└── (modules if applicable)
.terraform.lock.hcl ← commit to Git
5.2 terraform plan
Generates an execution plan — a dry run that shows exactly what Terraform will do WITHOUT making any changes.
# Simple plan
terraform plan
# Plan saved to a file (best practice)
terraform plan -out=m3.tfplan
Reading the plan:
+(green) → resource to create~(yellow) → resource to modify in place-(red) → resource to destroy-/+→ resource to destroy and recreate
5.3 terraform apply
Applies changes to the target environment.
# With a saved plan (recommended) — no confirmation prompt
terraform apply m3.tfplan
# Without a saved plan — generates a new plan and asks for confirmation
terraform apply
After a successful apply:
- Resources are created/modified in the target environment
- The state file (
terraform.tfstate) is updated - Outputs are displayed in the terminal
Re-running
terraform planorapplywithout modifying the code produces: “No changes. Infrastructure is up-to-date.”
5.4 terraform destroy
Destroys all infrastructure managed by the state. Use with caution.
terraform destroy
# Generate a saved destruction plan
terraform plan -destroy -out=destroy.tfplan
terraform apply destroy.tfplan
⚠️
terraform destroyis an alias forterraform apply -destroy. The-destroyflag onplangenerates a destruction plan with no prompts during the subsequent apply.
6. Input Variables and Output Values
6.1 Input variables
Input variables allow you to parameterize a configuration, making it dynamic and reusable.
# variables.tf
variable "aws_region" {
description = "The AWS region to deploy resources in"
type = string
default = "us-east-1"
}
variable "vpc_cidr_block" {
description = "The CIDR block for the VPC"
type = string
default = "10.0.0.0/16"
}
variable "http_port" {
description = "The HTTP port for the application"
type = number
# No default → must be provided
}
variable "ec2_instance_type" {
description = "The type of EC2 instance to launch"
type = string
# No default → must be provided
}
Available types:
| Type | Example |
|---|---|
string | "t3.micro", "us-east-1" |
number | 80, 443 |
bool | true, false |
list(string) | ["us-east-1a", "us-east-1b"] |
map(string) | { env = "dev", project = "globo" } |
object({...}) | Complex type with named properties |
Referencing a variable:
provider "aws" {
region = var.aws_region # Syntax: var.<variable_name>
}
6.2 Output values
Outputs extract information from a deployment: displayed in the terminal after an apply, stored in state, and usable by parent modules.
# outputs.tf
output "aws_instance_public_dns" {
description = "Public DNS hostname of the EC2 instance"
value = aws_instance.nginx1.public_dns
}
output "vpc_id" {
description = "ID of the created VPC"
value = aws_vpc.app.id
}
output "public_subnet_id" {
description = "ID of the public subnet"
value = aws_subnet.public_subnet1.id
}
Querying outputs:
# Display all outputs
terraform output
# Display a specific output
terraform output aws_instance_public_dns
6.3 Providing values to variables
Six ways to provide values, in ascending order of priority (last one wins):
| Priority | Method | Example |
|---|---|---|
| 1 (low) | default in the variable block | default = "us-east-1" |
| 2 | terraform.tfvars file (auto-loaded) | http_port = 80 |
| 3 | *.auto.tfvars files (auto-loaded) | prod.auto.tfvars |
| 4 | -var-file flag | terraform plan -var-file=prod.tfvars |
| 5 | -var flag | terraform plan -var="http_port=443" |
| 6 (high) | TF_VAR_* environment variables | export TF_VAR_http_port=443 |
| — | Interactive prompt (if no value provided) | Terraform asks the user |
Example terraform.tfvars file:
http_port = 80
ec2_instance_type = "t3.micro"
project = "globo-web"
environment = "dev"
billing_code = "PROJ-001"
6.4 fmt and validate commands
# Check formatting without modifying (useful in CI/CD)
terraform fmt -check
# Automatically reformat files
terraform fmt
# Validate syntax and logic (requires terraform init)
terraform validate
terraform fmtformats according to HashiCorp style guidelines (2-space indentation,=alignment).
terraform validatechecks both syntax AND logic (undeclared variables, invalid arguments, etc.).
7. Expressions, Functions, and Locals
7.1 Local values
Locals are computed values reusable within a configuration. Perfect for avoiding duplication and improving readability.
# locals.tf
locals {
# Naming prefix based on variables
naming_prefix = "${var.project}-${var.environment}"
# Common tags applied to all resources
common_tags = {
Company = var.company_name
Project = var.project
Environment = var.environment
BillingCode = var.billing_code
}
}
Referencing a local:
resource "aws_vpc" "app" {
cidr_block = var.vpc_cidr_block
tags = local.common_tags # Syntax: local.<name>
}
resource "aws_security_group" "nginx_sg" {
name = "${local.naming_prefix}-nginx-sg"
vpc_id = aws_vpc.app.id
}
7.2 Terraform Expressions
| Expression type | Description | Example |
|---|---|---|
| Literal | Static value | "us-east-1", 80, true |
| Reference | Points to another object | var.region, aws_vpc.app.id |
| Interpolation | Evaluates an expression inside a string | "${var.project}-${var.env}" |
| Operators | Arithmetic, logical, comparison | var.count > 2, !var.enabled |
| Conditional | If-then-else | var.env == "prod" ? "t3.large" : "t3.micro" |
| For | Transform collections | [for s in var.list : upper(s)] |
Interpolation example:
locals {
naming_prefix = "${var.project}-${var.environment}"
# If project="globo" and environment="dev" → "globo-dev"
}
Conditional example:
resource "aws_instance" "web" {
instance_type = var.environment == "prod" ? "t3.large" : "t3.micro"
}
7.3 Terraform Functions
Terraform includes more than 100 built-in functions. They do not need to be imported.
Syntax: function_name(argument1, argument2, ...)
Common functions:
| Function | Description | Example |
|---|---|---|
min(a, b, c) | Minimum value | min(5, 3, 8) → 3 |
max(a, b, c) | Maximum value | max(5, 3, 8) → 8 |
lower(str) | Converts to lowercase | lower("HELLO") → "hello" |
upper(str) | Converts to uppercase | upper("hello") → "HELLO" |
merge(map1, map2) | Merges maps | merge(local.common_tags, {Env="dev"}) |
templatefile(path, vars) | Renders a template | templatefile("./startup.tpl", {env=var.env}) |
file(path) | Reads a file | file("./script.sh") |
toset(list) | Converts a list to a set | toset(["a","b","a"]) → ["a","b"] |
lookup(map, key, default) | Looks up a map | lookup(var.amis, var.region, "default-ami") |
format(fmt, ...) | Formats a string | format("Hello, %s!", var.name) |
Example — templatefile for EC2 user_data:
# templates/startup_script.tpl
#!/bin/bash
sudo amazon-linux-extras install -y nginx1
sudo service nginx start
sudo cat > /usr/share/nginx/html/index.html << 'WEBSITE'
<html><body>
<h1>Environment: ${environment}</h1>
</body></html>
WEBSITE
# main.tf
resource "aws_instance" "nginx1" {
ami = nonsensitive(data.aws_ssm_parameter.amzn2_linux.value)
instance_type = var.ec2_instance_type
subnet_id = aws_subnet.public_subnet1.id
user_data = templatefile("./templates/startup_script.tpl", {
environment = var.environment
})
user_data_replace_on_change = true
}
7.4 terraform console
Interactive console for testing Terraform expressions and functions with access to the current state and variables.
terraform console
# Inside the console:
> min(5, 3, 8)
3
> lower("TACOCAT")
"tacocat"
> local.common_tags
{
"BillingCode" = "PROJ-001"
"Company" = "Globomantics"
"Environment" = "dev"
"Project" = "globo-web"
}
> exit # or Ctrl+D to quit
⚠️
terraform consolelocks the state while running. Always exit cleanly withexit.
8. Terraform State
8.1 What is state?
State is Terraform’s “memory”. It is a JSON file (terraform.tfstate) that:
- Maps configuration resources to real resources in the target environment
- Contains all attributes of each resource (IDs, IP addresses, DNS, etc.)
- Stores outputs
- Includes metadata (Terraform version, state serial number)
Process during terraform plan:
flowchart TD
A[Configuration .tf] --> C[Terraform Plan]
B[State Data] --> C
D[Query Cloud APIs\nRefresh attributes] --> C
C --> E{Differences?}
E -- Yes --> F[Execution Plan\nadd / change / destroy]
E -- No --> G[No changes needed]
F --> H[terraform apply]
H --> I[State updated]
⚠️ Never modify
terraform.tfstatemanually. Use Terraform commands to interact with state.
8.2 State backends
The state backend is the storage location for the state. Default: local file (terraform.tfstate).
| Backend | Locking | Workspaces | Encryption | Notes |
|---|---|---|---|---|
| local (default) | No | Limited | No | Good for getting started |
| AWS S3 | Yes (DynamoDB) | Yes | Yes (SSE) | Recommended for AWS |
| Azure Storage | Yes | Yes | Yes | Recommended for Azure |
| Google Cloud Storage | Yes | Yes | Yes | Recommended for GCP |
| HCP Terraform / Consul | Yes | Yes | Yes | HashiCorp solution |
S3 backend (partial configuration):
# terraform.tf
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
backend "s3" {
bucket = "my-terraform-state-bucket"
region = "us-east-1"
# key not defined → partial config, provided at terraform init
}
}
# Initialize with the partial configuration
terraform init -backend-config="key=globo-web-app/dev/terraform.tfstate"
8.3 State management commands
# Display full state (readable format)
terraform show
# Display full state as JSON
terraform show -json
# List all resources in state
terraform state list
# Show details of a specific resource
terraform state show aws_vpc.app
terraform state show aws_instance.nginx1
# Display all outputs
terraform output
# Display a specific output
terraform output aws_instance_public_dns
Other state manipulation commands:
| Command | Description |
|---|---|
terraform state mv <src> <dst> | Rename/move a resource in state |
terraform state rm <resource> | Remove a resource from state (without destroying it) |
terraform import <resource> <id> | Import an existing resource into state |
8.4 Migrating state to S3
# 1. Create the S3 bucket (with Terraform itself or AWS CLI)
# 2. Add the "s3" backend in terraform.tf
# 3. Re-initialize — Terraform offers to migrate the local state
terraform init
# Terraform asks:
# "Do you want to copy existing state to the new backend? (yes/no)"
# → yes
9. Reference Project: Globomantics Web App
Deployed architecture
graph TB
subgraph AWS["☁️ AWS — us-east-1"]
subgraph VPC["VPC 10.0.0.0/16"]
subgraph Subnet["Public Subnet 10.0.0.0/24"]
EC2["🖥️ EC2 Instance\nt3.micro\nNginx Web Server"]
end
SG["Security Group\nIngress: TCP 80\nEgress: All"]
RT["Route Table\n0.0.0.0/0 → IGW"]
end
IGW["🌐 Internet Gateway"]
end
Internet["🌍 Internet"] --> IGW --> RT --> SG --> EC2
SSM["SSM Parameter Store\nAMI Amazon Linux 2"] -.-> EC2
Complete base configuration (main.tf)
/*
Base Terraform configuration — Globomantics Web App
Deploys an EC2 instance with Nginx on AWS in us-east-1
*/
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
##################################################################################
# PROVIDERS
##################################################################################
provider "aws" {
region = var.aws_region
}
##################################################################################
# DATA
##################################################################################
data "aws_ssm_parameter" "amzn2_linux" {
name = "/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2"
}
##################################################################################
# RESOURCES — NETWORKING
##################################################################################
resource "aws_vpc" "app" {
cidr_block = var.vpc_cidr_block
enable_dns_hostnames = var.vpc_enable_dns_hostnames
tags = local.common_tags
}
resource "aws_internet_gateway" "app" {
vpc_id = aws_vpc.app.id
tags = local.common_tags
}
resource "aws_subnet" "public_subnet1" {
cidr_block = var.vpc_subnet_cidr
vpc_id = aws_vpc.app.id
map_public_ip_on_launch = var.map_public_ip_on_launch
tags = local.common_tags
}
resource "aws_route_table" "app" {
vpc_id = aws_vpc.app.id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.app.id
}
tags = local.common_tags
}
resource "aws_route_table_association" "app_subnet1" {
subnet_id = aws_subnet.public_subnet1.id
route_table_id = aws_route_table.app.id
}
##################################################################################
# RESOURCES — SECURITY GROUPS
##################################################################################
resource "aws_security_group" "nginx_sg" {
name = "${local.naming_prefix}-nginx-sg"
vpc_id = aws_vpc.app.id
ingress {
from_port = var.http_port
to_port = var.http_port
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
tags = local.common_tags
}
##################################################################################
# RESOURCES — EC2 INSTANCE
##################################################################################
resource "aws_instance" "nginx1" {
ami = nonsensitive(data.aws_ssm_parameter.amzn2_linux.value)
instance_type = var.ec2_instance_type
subnet_id = aws_subnet.public_subnet1.id
vpc_security_group_ids = [aws_security_group.nginx_sg.id]
user_data_replace_on_change = true
user_data = templatefile("./templates/startup_script.tpl", {
environment = var.environment
})
tags = merge(local.common_tags, {
Name = "${local.naming_prefix}-nginx"
})
}
Complete variables (variables.tf)
# AWS Region
variable "aws_region" {
description = "The AWS region to deploy resources in"
type = string
default = "us-east-1"
}
# VPC
variable "vpc_cidr_block" {
description = "The CIDR block for the VPC"
type = string
default = "10.0.0.0/16"
}
variable "vpc_enable_dns_hostnames" {
description = "Enable DNS hostnames in the VPC"
type = bool
default = true
}
variable "vpc_subnet_cidr" {
description = "The CIDR block for the public subnet"
type = string
default = "10.0.0.0/24"
}
variable "map_public_ip_on_launch" {
description = "Whether to map public IPs on launch for the subnet"
type = bool
default = true
}
# EC2 / Networking
variable "http_port" {
description = "The HTTP port for the application"
type = number
}
variable "ec2_instance_type" {
description = "The type of EC2 instance to launch"
type = string
}
# Tags / Naming
variable "company_name" {
description = "The name of the company"
type = string
default = "Globomantics"
}
variable "project" {
description = "The name of the project"
type = string
}
variable "environment" {
description = "The environment (dev, staging, prod)"
type = string
}
variable "billing_code" {
description = "The billing code for the project"
type = string
}
Variable values file (terraform.tfvars)
http_port = 80
ec2_instance_type = "t3.micro"
project = "globo-web"
environment = "dev"
billing_code = "PROJ-001"
Locals (locals.tf)
locals {
naming_prefix = "${var.project}-${var.environment}"
common_tags = {
Company = var.company_name
Project = var.project
Environment = var.environment
BillingCode = var.billing_code
}
}
Outputs (outputs.tf)
output "aws_instance_public_dns" {
description = "Public DNS hostname of the EC2 instance"
value = "http://${aws_instance.nginx1.public_dns}"
}
output "vpc_id" {
description = "ID of the created VPC"
value = aws_vpc.app.id
}
output "public_subnet_id" {
description = "ID of the public subnet"
value = aws_subnet.public_subnet1.id
}
10. Reference Diagrams
Terraform project structure
graph LR
subgraph WorkDir["Working Directory"]
TF["terraform.tf\n(required_providers,\nbackend)"]
MAIN["main.tf\n(provider, data,\nresources)"]
VARS["variables.tf\n(variable blocks)"]
OUTS["outputs.tf\n(output blocks)"]
LOCS["locals.tf\n(locals block)"]
TFVARS["terraform.tfvars\n(variable values)"]
TPL["templates/\n*.tpl"]
end
subgraph Generated[".terraform/ (generated)"]
LOCK[".terraform.lock.hcl\n(provider versions)"]
PROV["providers/\n(provider binaries)"]
STATE["terraform.tfstate\n(local state)"]
end
WorkDir --> Generated
Providers and Resources
flowchart TD
Registry["🌐 Terraform Registry\nregistry.terraform.io"] -->|terraform init| ProvPlugin
subgraph TF["Terraform"]
Config["Configuration .tf"] --> Core["Terraform Core"]
ProvPlugin["Provider Plugin\n(e.g. hashicorp/aws)"] --> Core
StateData["State Data\n(.tfstate)"] --> Core
end
Core -->|API calls| AWS["☁️ AWS API"]
Core -->|API calls| Azure["☁️ Azure API"]
Core -->|API calls| GCP["☁️ GCP API"]
Core -->|API calls| Other["☁️ Other APIs"]
Complete workflow with commands
sequenceDiagram
participant Dev as 👤 Developer
participant TF as Terraform CLI
participant Registry as Terraform Registry
participant Cloud as Cloud Provider (AWS)
participant State as State Backend
Dev->>TF: terraform init
TF->>Registry: Download provider plugins
Registry-->>TF: hashicorp/aws v5.x
TF-->>Dev: Initialized!
Dev->>TF: terraform plan -out=plan.tfplan
TF->>State: Load current state
TF->>Cloud: Refresh resource attributes
Cloud-->>TF: Current attributes
TF-->>Dev: Execution plan (+ add, ~ change, - destroy)
Dev->>TF: terraform apply plan.tfplan
TF->>Cloud: Create/Modify/Destroy resources
Cloud-->>TF: Results
TF->>State: Update state
TF-->>Dev: Apply complete! Outputs displayed
Dev->>TF: terraform destroy
TF->>Cloud: Destroy all resources
TF->>State: Clear state
TF-->>Dev: Destroy complete!
11. Reference Tables
Essential Terraform commands
| Command | Description |
|---|---|
terraform init | Initialize the configuration (providers, backend, modules) |
terraform plan | Preview changes |
terraform plan -out=<file> | Save the plan to a file |
terraform apply | Apply changes (with prompt) |
terraform apply <planfile> | Apply a saved plan (no prompt) |
terraform destroy | Destroy all infrastructure |
terraform fmt | Reformat .tf files |
terraform fmt -check | Check formatting without modifying |
terraform validate | Validate syntax and logic |
terraform show | Display state in readable format |
terraform show -json | Display state as JSON |
terraform state list | List resources in state |
terraform state show <res> | Details of a state resource |
terraform output | Display all outputs |
terraform output <name> | Display a specific output |
terraform console | Interactive console for testing expressions |
terraform providers | List providers in use |
terraform version | Display Terraform version |
HCL block reference
| Block | Labels | Description |
|---|---|---|
terraform {} | None | Configuration metadata |
provider "<name>" {} | 1 (provider name) | Provider instance |
resource "<type>" "<name>" {} | 2 (type + name) | Resource to create/manage |
data "<type>" "<name>" {} | 2 (type + name) | Data source (read-only) |
variable "<name>" {} | 1 (name) | Input variable |
output "<name>" {} | 1 (name) | Output value |
locals {} | None | Computed local values |
module "<name>" {} | 1 (name) | Module call |
Common variable block arguments
| Argument | Type | Description |
|---|---|---|
type | Type constraint | Variable type (string, number, bool, list(...), map(...)) |
description | string | Variable documentation |
default | any | Default value (makes the variable optional) |
sensitive | bool | Masks the value in outputs and state |
validation {} | block | Custom validation rules |
HCL reference syntax
| Syntax | Description | Example |
|---|---|---|
var.<name> | Variable reference | var.aws_region |
local.<name> | Local value reference | local.naming_prefix |
data.<type>.<name>.<attr> | Data source attribute | data.aws_ssm_parameter.amzn2_linux.value |
<type>.<name>.<attr> | Resource attribute | aws_vpc.app.id |
"${expression}" | String interpolation | "${var.project}-${var.env}" |
12. Next Steps
Here are the recommended next steps for continuing your Terraform journey:
graph LR
A["✅ Terraform:\nGetting Started\n(this course)"] --> B["Terraform:\nVariables and Outputs\n(validation, complex types,\nsensitive values)"]
A --> C["Terraform:\nModules\n(consuming and creating\nreusable modules)"]
A --> D["Terraform:\nAdvanced HCL\n(count, for_each,\nfor expressions)"]
B --> E["Terraform:\nState Management"]
C --> E
D --> E
Search Terms
terraform · infrastructure · ci/cd · devops · block · reference · state · values · commands · hcl · variables · iac · architecture · configuration · expressions · functions · input · locals · output · syntax · variable · workflow