Beginner

Terraform: Getting Started

Infrastructure as Code with Terraform — the workflow, HCL, variables, outputs and state on AWS.

Target platform: AWS (us-east-1) · Tool: Terraform Community Edition · Language: HCL (HashiCorp Configuration Language)


Table of Contents

  1. Introduction to Infrastructure as Code (IaC)
  2. What is Terraform?
  3. The Terraform Workflow
  4. Configuration Files and HCL Syntax
  5. Deploying Infrastructure
  6. Input Variables and Output Values
  7. Expressions, Functions, and Locals
  8. Terraform State
  9. Reference Project: Globomantics Web App
  10. Reference Diagrams
  11. Reference Tables
  12. 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

ConceptDescription
Defined in codeInfrastructure is described in files (JSON, HCL, Python, YAML…)
Stored in source controlGit + GitHub for versioning, tracking, and collaboration
Declarative vs ImperativeYou describe the desired state, not the steps to get there
IdempotentRunning the same code multiple times always produces the same final state
ReusableThe 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

EditionDescription
Terraform Community EditionFree, open-source (Business Source License) — used in this course
HCP TerraformHashiCorp SaaS service (formerly Terraform Cloud)
Terraform EnterpriseSelf-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

PhaseCommandDescription
Write(editing .tf files)Write or modify HCL configuration files
Initterraform initInitialize: download providers, prepare state
Planterraform planGenerate an execution plan (dry run)
Applyterraform applyApply changes to the target environment
Destroyterraform destroyDestroy 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 .tf extension.

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 resource
  • ami, 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 .tf file 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:

  1. Downloads the required provider plugins (e.g. hashicorp/aws)
  2. Creates the .terraform.lock.hcl file (exact provider versions — commit to Git)
  3. Prepares the state backend
  4. 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 plan or apply without 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 destroy is an alias for terraform apply -destroy. The -destroy flag on plan generates 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:

TypeExample
string"t3.micro", "us-east-1"
number80, 443
booltrue, 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):

PriorityMethodExample
1 (low)default in the variable blockdefault = "us-east-1"
2terraform.tfvars file (auto-loaded)http_port = 80
3*.auto.tfvars files (auto-loaded)prod.auto.tfvars
4-var-file flagterraform plan -var-file=prod.tfvars
5-var flagterraform plan -var="http_port=443"
6 (high)TF_VAR_* environment variablesexport 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 fmt formats according to HashiCorp style guidelines (2-space indentation, = alignment).
terraform validate checks 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 typeDescriptionExample
LiteralStatic value"us-east-1", 80, true
ReferencePoints to another objectvar.region, aws_vpc.app.id
InterpolationEvaluates an expression inside a string"${var.project}-${var.env}"
OperatorsArithmetic, logical, comparisonvar.count > 2, !var.enabled
ConditionalIf-then-elsevar.env == "prod" ? "t3.large" : "t3.micro"
ForTransform 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:

FunctionDescriptionExample
min(a, b, c)Minimum valuemin(5, 3, 8)3
max(a, b, c)Maximum valuemax(5, 3, 8)8
lower(str)Converts to lowercaselower("HELLO")"hello"
upper(str)Converts to uppercaseupper("hello")"HELLO"
merge(map1, map2)Merges mapsmerge(local.common_tags, {Env="dev"})
templatefile(path, vars)Renders a templatetemplatefile("./startup.tpl", {env=var.env})
file(path)Reads a filefile("./script.sh")
toset(list)Converts a list to a settoset(["a","b","a"])["a","b"]
lookup(map, key, default)Looks up a maplookup(var.amis, var.region, "default-ami")
format(fmt, ...)Formats a stringformat("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 console locks the state while running. Always exit cleanly with exit.


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.tfstate manually. 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).

BackendLockingWorkspacesEncryptionNotes
local (default)NoLimitedNoGood for getting started
AWS S3Yes (DynamoDB)YesYes (SSE)Recommended for AWS
Azure StorageYesYesYesRecommended for Azure
Google Cloud StorageYesYesYesRecommended for GCP
HCP Terraform / ConsulYesYesYesHashiCorp 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:

CommandDescription
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

CommandDescription
terraform initInitialize the configuration (providers, backend, modules)
terraform planPreview changes
terraform plan -out=<file>Save the plan to a file
terraform applyApply changes (with prompt)
terraform apply <planfile>Apply a saved plan (no prompt)
terraform destroyDestroy all infrastructure
terraform fmtReformat .tf files
terraform fmt -checkCheck formatting without modifying
terraform validateValidate syntax and logic
terraform showDisplay state in readable format
terraform show -jsonDisplay state as JSON
terraform state listList resources in state
terraform state show <res>Details of a state resource
terraform outputDisplay all outputs
terraform output <name>Display a specific output
terraform consoleInteractive console for testing expressions
terraform providersList providers in use
terraform versionDisplay Terraform version

HCL block reference

BlockLabelsDescription
terraform {}NoneConfiguration 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 {}NoneComputed local values
module "<name>" {}1 (name)Module call

Common variable block arguments

ArgumentTypeDescription
typeType constraintVariable type (string, number, bool, list(...), map(...))
descriptionstringVariable documentation
defaultanyDefault value (makes the variable optional)
sensitiveboolMasks the value in outputs and state
validation {}blockCustom validation rules

HCL reference syntax

SyntaxDescriptionExample
var.<name>Variable referencevar.aws_region
local.<name>Local value referencelocal.naming_prefix
data.<type>.<name>.<attr>Data source attributedata.aws_ssm_parameter.amzn2_linux.value
<type>.<name>.<attr>Resource attributeaws_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

Interested in this course?

Contact us to book it or get a custom training plan for your team.