CI/CD & DevOps

Infrastructure as Code Basics

Define your infrastructure in version-controlled configuration files for reproducibility and auditability.

What Infrastructure as Code Is

Infrastructure as Code (IaC) means defining your servers, databases, networks, and cloud resources in configuration files that are version-controlled, peer-reviewed, and applied automatically — exactly like application code.

Without IaC: infrastructure is configured by clicking through cloud consoles. Changes are undocumented, hard to reproduce, and easy to get wrong.

With IaC: infrastructure changes go through code review. Every change is documented in git history. You can recreate the entire infrastructure from scratch in minutes.

IaC Tools

Terraform — The most widely adopted IaC tool. Cloud-agnostic (works with AWS, GCP, Azure, Vercel, and hundreds of providers). Declarative: you describe the desired state, Terraform figures out how to achieve it.

Pulumi — Uses real programming languages (TypeScript, Python, Go) instead of a custom syntax. Appealing to developers who find YAML/HCL limiting.

AWS CDK — AWS-specific IaC using TypeScript or Python. Generates CloudFormation templates. Excellent if you are AWS-only.

Docker + Docker Compose — IaC at the application level. Your Dockerfile and docker-compose.yml are IaC for application infrastructure.

Terraform Basics

hcl
# main.tf

# Configure the AWS provider
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
}

provider "aws" {
  region = var.aws_region
}

# Variables
variable "aws_region" {
  default = "us-east-1"
}

variable "environment" {
  type = string
}

# An S3 bucket for static assets
resource "aws_s3_bucket" "assets" {
  bucket = "myapp-assets-${var.environment}"

  tags = {
    Environment = var.environment
    ManagedBy   = "Terraform"
  }
}

# Make the bucket public (for static assets like images)
resource "aws_s3_bucket_public_access_block" "assets" {
  bucket = aws_s3_bucket.assets.id

  block_public_acls       = false
  block_public_policy     = false
  ignore_public_acls      = false
  restrict_public_buckets = false
}

# Output the bucket name
output "assets_bucket_name" {
  value = aws_s3_bucket.assets.bucket
}

The Terraform Workflow

bash
# Initialize (download providers)
terraform init

# Preview changes (shows what will be created/modified/destroyed)
terraform plan

# Apply changes (creates/modifies/destroys resources)
terraform apply

# Destroy all resources
terraform destroy

Always run terraform plan before terraform apply. Review every planned change — destroyed resources cannot be recovered.

When IaC Is Overkill

IaC has real overhead: learning the tool, managing state, debugging provider issues. It pays off at scale, but for small projects:

  • Solo project on Vercel? You don't need Terraform. Vercel's UI is perfectly sufficient.
  • Single Supabase database? Use Supabase's dashboard or migrations.
  • Early prototyping? Move fast, use consoles, add IaC when the project stabilizes.

The right time to add IaC is when: you have a team and need infrastructure changes reviewed, you're managing multiple environments (dev/staging/prod), or you need disaster recovery capability.

Key Takeaways

  • IaC defines infrastructure in version-controlled files that are reproducible and peer-reviewed
  • Terraform is the most widely used tool — cloud-agnostic, declarative, large ecosystem
  • Always run terraform plan before terraform apply to review what will change
  • Docker Compose is IaC at the application level — already in use for most teams
  • IaC is not necessary for every project — Vercel, Netlify, and Supabase UIs are IaC enough for many applications

Example

hcl
# Terraform: S3 bucket + CloudFront CDN
terraform {
  required_providers {
    aws = { source = "hashicorp/aws", version = "~> 5.0" }
  }
}

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

resource "aws_s3_bucket" "static_assets" {
  bucket = "myapp-static-assets"
}

resource "aws_cloudfront_distribution" "cdn" {
  origin {
    domain_name = aws_s3_bucket.static_assets.bucket_regional_domain_name
    origin_id   = "S3Origin"
  }

  enabled             = true
  default_root_object = "index.html"

  default_cache_behavior {
    allowed_methods  = ["GET", "HEAD"]
    cached_methods   = ["GET", "HEAD"]
    target_origin_id = "S3Origin"
    viewer_protocol_policy = "redirect-to-https"
    forwarded_values {
      query_string = false
      cookies { forward = "none" }
    }
  }

  restrictions {
    geo_restriction { restriction_type = "none" }
  }

  viewer_certificate {
    cloudfront_default_certificate = true
  }
}

output "cdn_url" {
  value = aws_cloudfront_distribution.cdn.domain_name
}
Try it yourself — HCL

Docker, AWS, Vercel, Netlify, GitHub, GitHub Actions are trademarks of Docker, Inc., Amazon.com, Inc., Vercel, Inc., Netlify, Inc., Microsoft Corporation. DevForge Academy is not affiliated with, endorsed by, or sponsored by these companies. Referenced for educational purposes only. See full disclaimers