Terraform is infrastructure as code: it lets you define servers, databases, DNS records, and certificates in text files that you commit to git, review in pull requests, and apply with a single command. As an application developer, you should know enough Terraform to manage your own infrastructure without depending entirely on a dedicated ops person.
What Problem Terraform Solves
Without infrastructure as code, infrastructure is configured manually through cloud provider dashboards. This creates two problems: the configuration is invisible (nobody knows exactly what settings were chosen without logging into every dashboard) and it is not reproducible (recreating the same infrastructure for a new environment requires remembering every manual step).
Terraform solves both problems. Your infrastructure configuration is in HCL (HashiCorp Configuration Language) files. Those files are committed to git. To recreate your entire infrastructure in a new environment, you run terraform apply. To make a change, you edit a file, review the diff, and apply it.
Core Concepts
Providers: Terraform providers are plugins that know how to create resources in a particular service. There are providers for AWS, Google Cloud, Azure, Vercel, Cloudflare, GitHub, PlanetScale, Stripe, and hundreds more. Each provider is declared in your Terraform configuration and downloaded by terraform init.
terraform {
required_providers {
vercel = {
source = "vercel/vercel"
version = "~> 1.0"
}
cloudflare = {
source = "cloudflare/cloudflare"
version = "~> 4.0"
}
}
}
Resources: resources are the things you create: a Vercel project, a Cloudflare DNS record, an Upstash Redis instance. Each resource has a type (from the provider) and a configuration block.
resource "vercel_project" "web" {
name = "my-app"
framework = "nextjs"
git_repository = {
type = "github"
repo = "myorg/my-app"
}
}
Data sources: data sources read existing resources that Terraform did not create. Useful for referencing a zone ID in Cloudflare without hard-coding it.
data "cloudflare_zone" "main" {
name = "example.com"
}
Variables: parameterize your configuration so the same code works for different environments (staging, production) with different values.
variable "environment" {
type = string
default = "production"
}
Outputs: expose values from your Terraform resources for use in other systems or by humans:
output "deployment_url" {
value = vercel_project.web.url
}
The Workflow: init, plan, apply, destroy
terraform init: downloads the required providers and initializes the working directory. Run this once when setting up the project, and again when you add new providers.
terraform plan: Terraform reads your configuration, compares it to the current state of your infrastructure, and shows you what changes would be made. This is a dry run. No changes are made. Read the plan carefully before applying.
terraform apply: applies the changes shown in the plan. Terraform prompts you to confirm before making any changes. After you confirm, it creates, updates, or destroys resources to match your configuration.
terraform destroy: destroys all resources managed by your configuration. Use carefully.
State Management
Terraform tracks what it has created in a state file (terraform.tfstate). This file maps your HCL configuration to real-world resource IDs. Without it, Terraform does not know what exists.
Why local state is dangerous for teams: if two team members apply Terraform simultaneously from their local machines with different state files, they will create conflicting resources or destroy each other's changes. State must be shared.
Remote state: store state in a backend that supports locking. The most common options:
- S3 + DynamoDB: store the state file in an S3 bucket, use DynamoDB for locking. The traditional AWS approach.
- Terraform Cloud: HCP Terraform (formerly Terraform Cloud) provides remote state, locking, and a web UI for plan/apply history. Free tier includes 500 resource hours per month.
- GitLab CI / GitHub Actions backend: some CI providers offer Terraform state backends natively.
terraform {
backend "s3" {
bucket = "my-terraform-state"
key = "production/terraform.tfstate"
region = "us-east-1"
dynamodb_table = "terraform-locks"
}
}
Real Use Case: Next.js App with Vercel + Cloudflare + Upstash
A practical example of what Terraform manages for a Next.js application:
# Vercel project
resource "vercel_project" "web" {
name = "my-nextjs-app"
framework = "nextjs"
}
# Environment variables for the Vercel project
resource "vercel_project_environment_variable" "redis_url" {
project_id = vercel_project.web.id
key = "UPSTASH_REDIS_REST_URL"
value = upstash_redis_database.cache.rest_url
target = ["production", "preview"]
}
# Upstash Redis database
resource "upstash_redis_database" "cache" {
database_name = "my-app-cache"
region = "us-east-1"
tls = true
}
# Cloudflare DNS pointing to Vercel
resource "cloudflare_record" "web" {
zone_id = data.cloudflare_zone.main.id
name = "app"
value = "cname.vercel-dns.com"
type = "CNAME"
proxied = true
}
Running terraform apply creates all of this in one command. Running it again after changing the Redis region updates only the Redis database. Running terraform plan before any change shows exactly what will be modified.
When Terraform Is Overkill
Terraform adds overhead. For a single-developer project or a simple app with one deployment, managing everything through the Vercel and Cloudflare dashboards is faster and simpler. The complexity of Terraform becomes worthwhile when:
- You have multiple environments (staging and production) that need identical configuration
- Multiple team members need to make infrastructure changes safely
- You need to recreate your infrastructure reproducibly (disaster recovery, new region)
- Your infrastructure is complex enough that the dashboard-clicking approach loses track of what was changed and when
When Terraform Is Essential
For any team beyond two or three developers, Terraform (or an equivalent tool like Pulumi) is essential. Infrastructure changes become part of your normal code review process. You catch mistakes before they hit production. You have an audit log of every infrastructure change. And you can on-board new engineers to your infrastructure without giving them dashboard access to click through.
Keep Reading
- Vercel vs Cloudflare Pages vs Netlify — the platforms Terraform manages
- GitHub Actions Guide for Developers — running Terraform in CI/CD pipelines
- Coolify vs Fly.io vs Render — self-hosted alternatives if you want to avoid cloud provider complexity
Pristren builds AI-powered software for teams. Zlyqor is our all-in-one workspace — chat, projects, time tracking, AI meeting summaries, and invoicing — in one tool. Try it free.