Skip to content
Codeloom
DevOps

Getting Started with Terraform

Learn Terraform from scratch — providers, resources, variables, state, modules, and deploying your first infrastructure as code.

·3 min read · By Codeloom
Beginner 12 min read

What you'll learn

  • What Terraform is and how it manages infrastructure
  • HCL syntax: providers, resources, variables, outputs
  • The plan/apply/destroy lifecycle
  • State management and basic modules

Prerequisites

  • Basic understanding of cloud services (AWS, GCP, or Azure)
  • Comfort with the command line

Terraform by HashiCorp lets you define infrastructure as code in .tf files. You describe what you want, and Terraform figures out how to create, update, or delete resources to match.

Install and setup

# macOS
brew install terraform

# Verify
terraform --version

Your first configuration

Create a directory and a main.tf file:

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

provider "aws" {
  region = "us-east-1"
}

resource "aws_s3_bucket" "my_bucket" {
  bucket = "my-terraform-demo-bucket-12345"

  tags = {
    Environment = "dev"
    ManagedBy   = "terraform"
  }
}

The Terraform workflow

terraform init     # Download providers
terraform plan     # Preview changes
terraform apply    # Create/update resources
terraform destroy  # Tear down everything

terraform plan shows what will be created, modified, or destroyed — review it before applying.

Variables

variable "region" {
  description = "AWS region"
  type        = string
  default     = "us-east-1"
}

variable "environment" {
  description = "Deployment environment"
  type        = string
}

provider "aws" {
  region = var.region
}

Set variables via CLI, environment variables, or .tfvars files:

terraform apply -var="environment=staging"

Or create terraform.tfvars:

region      = "us-west-2"
environment = "production"

Variable types

variable "port" {
  type    = number
  default = 8080
}

variable "tags" {
  type = map(string)
  default = {
    Team = "platform"
  }
}

variable "availability_zones" {
  type    = list(string)
  default = ["us-east-1a", "us-east-1b"]
}

Outputs

Expose values after apply.

output "bucket_arn" {
  description = "ARN of the S3 bucket"
  value       = aws_s3_bucket.my_bucket.arn
}

output "bucket_domain" {
  value = aws_s3_bucket.my_bucket.bucket_domain_name
}

After terraform apply, outputs print to the console and are queryable:

terraform output bucket_arn

State

Terraform stores the current state of your infrastructure in terraform.tfstate. This file maps your configuration to real resources.

Never edit state manually. Use terraform state commands:

terraform state list              # List all resources
terraform state show aws_s3_bucket.my_bucket  # Details
terraform state rm aws_s3_bucket.my_bucket    # Remove from state

Remote state

For teams, store state in a shared backend:

terraform {
  backend "s3" {
    bucket = "my-terraform-state"
    key    = "prod/terraform.tfstate"
    region = "us-east-1"
  }
}

Data sources

Read existing resources that Terraform does not manage.

data "aws_ami" "ubuntu" {
  most_recent = true
  owners      = ["099720109477"] # Canonical

  filter {
    name   = "name"
    values = ["ubuntu/images/hvm-ssd/ubuntu-*-22.04-amd64-server-*"]
  }
}

resource "aws_instance" "web" {
  ami           = data.aws_ami.ubuntu.id
  instance_type = "t3.micro"
}

Modules

Group related resources into reusable modules.

modules/
  vpc/
    main.tf
    variables.tf
    outputs.tf

Use a module:

module "vpc" {
  source = "./modules/vpc"

  cidr_block = "10.0.0.0/16"
  name       = "production"
}

Lifecycle rules

resource "aws_instance" "web" {
  ami           = data.aws_ami.ubuntu.id
  instance_type = "t3.micro"

  lifecycle {
    create_before_destroy = true
    prevent_destroy       = true
    ignore_changes        = [tags]
  }
}

Summary

Terraform lets you version-control your infrastructure. Define resources in HCL, preview with plan, apply with apply. Use variables for flexibility, outputs to expose values, modules for reuse, and remote state for team collaboration. Start small — a single resource — and grow from there.